home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / misccmds.c < prev    next >
C/C++ Source or Header  |  1996-06-13  |  87KB  |  3,906 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * misccmds.c: functions that didn't seem to fit elsewhere
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "option.h"
  17. #ifdef HAVE_FCNTL_H
  18. # include <fcntl.h>            /* for chdir() */
  19. #endif
  20.  
  21. static int get_indent_str __ARGS((char_u *ptr));
  22. static void check_status __ARGS((BUF *));
  23.  
  24. /*
  25.  * count the size of the indent in the current line
  26.  */
  27.     int
  28. get_indent()
  29. {
  30.     return get_indent_str(ml_get_curline());
  31. }
  32.  
  33. /*
  34.  * count the size of the indent in line "lnum"
  35.  */
  36.     int
  37. get_indent_lnum(lnum)
  38.     linenr_t    lnum;
  39. {
  40.     return get_indent_str(ml_get(lnum));
  41. }
  42.  
  43. /*
  44.  * count the size of the indent in line "ptr"
  45.  */
  46.     static int
  47. get_indent_str(ptr)
  48.     register char_u *ptr;
  49. {
  50.     register int count = 0;
  51.  
  52.     for ( ; *ptr; ++ptr)
  53.     {
  54.         if (*ptr == TAB)    /* count a tab for what it is worth */
  55.             count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
  56.         else if (*ptr == ' ')
  57.             ++count;            /* count a space for one */
  58.         else
  59.             break;
  60.     }
  61.     return (count);
  62. }
  63.  
  64. /*
  65.  * set the indent of the current line
  66.  * leaves the cursor on the first non-blank in the line
  67.  */
  68.     void
  69. set_indent(size, del_first)
  70.     register int    size;
  71.     int             del_first;
  72. {
  73.     int                oldstate = State;
  74.     register int    c;
  75.  
  76.     State = INSERT;                    /* don't want REPLACE for State */
  77.     curwin->w_cursor.col = 0;
  78.     if (del_first)                    /* delete old indent */
  79.     {
  80.                                     /* vim_iswhite() is a define! */
  81.         while ((c = gchar_cursor()), vim_iswhite(c))
  82.             (void)delchar(FALSE);
  83.     }
  84.     if (!curbuf->b_p_et)            /* if 'expandtab' is set, don't use TABs */
  85.         while (size >= (int)curbuf->b_p_ts)
  86.         {
  87.             ins_char(TAB);
  88.             size -= (int)curbuf->b_p_ts;
  89.         }
  90.     while (size)
  91.     {
  92.         ins_char(' ');
  93.         --size;
  94.     }
  95.     State = oldstate;
  96. }
  97.  
  98. #if defined(CINDENT) || defined(SMARTINDENT)
  99.  
  100. static int is_cinword __ARGS((char_u *line));
  101.  
  102. /*
  103.  * Return TRUE if the string "line" starts with a word from 'cinwords'.
  104.  */
  105.     static int
  106. is_cinword(line)
  107.     char_u        *line;
  108. {
  109.     char_u    *cinw;
  110.     char_u    *cinw_buf;
  111.     int        cinw_len;
  112.     int        retval = FALSE;
  113.     int        len;
  114.  
  115.     cinw_len = STRLEN(curbuf->b_p_cinw) + 1;
  116.     cinw_buf = alloc((unsigned)cinw_len);
  117.     if (cinw_buf != NULL)
  118.     {
  119.         line = skipwhite(line);
  120.         for (cinw = curbuf->b_p_cinw; *cinw; )
  121.         {
  122.             len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
  123.             if (STRNCMP(line, cinw_buf, len) == 0 &&
  124.                        (!iswordchar(line[len]) || !iswordchar(line[len - 1])))
  125.             {
  126.                 retval = TRUE;
  127.                 break;
  128.             }
  129.         }
  130.         vim_free(cinw_buf);
  131.     }
  132.     return retval;
  133. }
  134. #endif
  135.  
  136. /*
  137.  * Opencmd
  138.  *
  139.  * Add a new line below or above the current line.
  140.  * Caller must take care of undo.
  141.  *
  142.  * Return TRUE for success, FALSE for failure
  143.  */
  144.  
  145.     int
  146. Opencmd(dir, redraw, del_spaces)
  147.     int         dir;            /* FORWARD or BACKWARD */
  148.     int            redraw;            /* redraw afterwards */
  149.     int            del_spaces;        /* delete spaces after cursor */
  150. {
  151.     char_u  *saved_line;        /* copy of the original line */
  152.     char_u    *p_extra = NULL;    /* what goes to next line */
  153.     int        extra_len = 0;        /* length of p_extra string */
  154.     FPOS    old_cursor;         /* old cursor position */
  155.     int        newcol = 0;            /* new cursor column */
  156.     int     newindent = 0;        /* auto-indent of the new line */
  157.     int        n;
  158.     int        trunc_line = FALSE;    /* truncate current line afterwards */
  159.     int        retval = FALSE;        /* return value, default is FAIL */
  160.     int        lead_len;            /* length of comment leader */
  161.     char_u    *lead_flags;        /* position in 'comments' for comment leader */
  162.     char_u    *leader = NULL;        /* copy of comment leader */
  163.     char_u    *allocated = NULL;    /* allocated memory */
  164.     char_u    *p;
  165.     int        saved_char = NUL;    /* init for GCC */
  166.     FPOS    *pos;
  167.     int        old_plines = 0;        /* init for GCC */
  168.     int        new_plines = 0;        /* init for GCC */
  169. #ifdef SMARTINDENT
  170.     int        no_si = FALSE;        /* reset did_si afterwards */
  171.     int        first_char = NUL;    /* init for GCC */
  172. #endif
  173.  
  174.     /*
  175.      * make a copy of the current line so we can mess with it
  176.      */
  177.     saved_line = strsave(ml_get_curline());
  178.     if (saved_line == NULL)            /* out of memory! */
  179.         return FALSE;
  180.  
  181.     if (State == INSERT || State == REPLACE)
  182.     {
  183.         p_extra = saved_line + curwin->w_cursor.col;
  184. #ifdef SMARTINDENT
  185.         if (curbuf->b_p_si)            /* need first char after new line break */
  186.         {
  187.             p = skipwhite(p_extra);
  188.             first_char = *p;
  189.         }
  190. #endif
  191.         extra_len = STRLEN(p_extra);
  192.         saved_char = *p_extra;
  193.         *p_extra = NUL;
  194.     }
  195.  
  196.     u_clearline();                /* cannot do "U" command when adding lines */
  197. #ifdef SMARTINDENT
  198.     did_si = FALSE;
  199. #endif
  200.  
  201.     /*
  202.      * If 'autoindent' and/or 'smartindent' is set, try to figure out what
  203.      * indent to use for the new line.
  204.      */
  205.     if (curbuf->b_p_ai
  206. #ifdef SMARTINDENT
  207.                         || curbuf->b_p_si
  208. #endif
  209.                                             )
  210.     {
  211.         /*
  212.          * count white space on current line
  213.          */
  214.         newindent = get_indent();
  215.         if (newindent == 0)
  216.             newindent = old_indent;        /* for ^^D command in insert mode */
  217.         old_indent = 0;
  218.  
  219.         /*
  220.          * If we just did an auto-indent, then we didn't type anything on
  221.          * the prior line, and it should be truncated.
  222.          */
  223.         if (dir == FORWARD && did_ai)
  224.             trunc_line = TRUE;
  225.  
  226. #ifdef SMARTINDENT
  227.         /*
  228.          * Do smart indenting.
  229.          * In insert/replace mode (only when dir == FORWARD)
  230.          * we may move some text to the next line. If it starts with '{'
  231.          * don't add an indent. Fixes inserting a NL before '{' in line
  232.          *         "if (condition) {"
  233.          */
  234.         else if (curbuf->b_p_si && *saved_line != NUL &&
  235.                                        (p_extra == NULL || first_char != '{'))
  236.         {
  237.             char_u    *ptr;
  238.             char_u    last_char;
  239.  
  240.             old_cursor = curwin->w_cursor;
  241.             ptr = saved_line;
  242.             lead_len = get_leader_len(ptr, NULL);
  243.             if (dir == FORWARD)
  244.             {
  245.                 /*
  246.                  * Skip preprocessor directives, unless they are
  247.                  * recognised as comments.
  248.                  */
  249.                 if (lead_len == 0 && ptr[0] == '#')
  250.                 {
  251.                     while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
  252.                         ptr = ml_get(--curwin->w_cursor.lnum);
  253.                     newindent = get_indent();
  254.                 }
  255.                 lead_len = get_leader_len(ptr, NULL);
  256.                 if (lead_len > 0)
  257.                 {
  258.                     /*
  259.                      * This case gets the following right:
  260.                      *        \*
  261.                      *         * A comment (read "\" as "/").
  262.                      *         *\
  263.                      * #define IN_THE_WAY
  264.                      *        This should line up here;
  265.                      */
  266.                     p = skipwhite(ptr);
  267.                     if (p[0] == '/' && p[1] == '*')
  268.                         p++;
  269.                     if (p[0] == '*')
  270.                     {
  271.                         for (p++; *p; p++)
  272.                         {
  273.                             if (p[0] == '/' && p[-1] == '*')
  274.                             {
  275.                                 /*
  276.                                  * End of C comment, indent should line up
  277.                                  * with the line containing the start of
  278.                                  * the comment
  279.                                  */
  280.                                 curwin->w_cursor.col = p - ptr;
  281.                                 if ((pos = findmatch(NUL)) != NULL)
  282.                                 {
  283.                                     curwin->w_cursor.lnum = pos->lnum;
  284.                                     newindent = get_indent();
  285.                                 }
  286.                             }
  287.                         }
  288.                     }
  289.                 }
  290.                 else    /* Not a comment line */
  291.                 {
  292.                     /* Find last non-blank in line */
  293.                     p = ptr + STRLEN(ptr) - 1;
  294.                     while (p > ptr && vim_iswhite(*p))
  295.                         --p;
  296.                     last_char = *p;
  297.  
  298.                     /*
  299.                      * find the character just before the '{' or ';'
  300.                      */
  301.                     if (last_char == '{' || last_char == ';')
  302.                     {
  303.                         if (p > ptr)
  304.                             --p;
  305.                         while (p > ptr && vim_iswhite(*p))
  306.                             --p;
  307.                     }
  308.                     /*
  309.                      * Try to catch lines that are split over multiple
  310.                      * lines.  eg:
  311.                      *        if (condition &&
  312.                      *                    condition) {
  313.                      *            Should line up here!
  314.                      *        }
  315.                      */
  316.                     if (*p == ')')
  317.                     {
  318.                         curwin->w_cursor.col = p - ptr;
  319.                         if ((pos = findmatch('(')) != NULL)
  320.                         {
  321.                             curwin->w_cursor.lnum = pos->lnum;
  322.                             newindent = get_indent();
  323.                             ptr = ml_get_curline();
  324.                         }
  325.                     }
  326.                     /*
  327.                      * If last character is '{' do indent, without
  328.                      * checking for "if" and the like.
  329.                      */
  330.                     if (last_char == '{')
  331.                     {
  332.                         did_si = TRUE;    /* do indent */
  333.                         no_si = TRUE;    /* don't delete it when '{' typed */
  334.                     }
  335.                     /*
  336.                      * Look for "if" and the like, use 'cinwords'.
  337.                      * Don't do this if the previous line ended in ';' or
  338.                      * '}'.
  339.                      */
  340.                     else if (last_char != ';' && last_char != '}' &&
  341.                                                             is_cinword(ptr))
  342.                         did_si = TRUE;
  343.                 }
  344.             }
  345.             else /* dir == BACKWARD */
  346.             {
  347.                 /*
  348.                  * Skip preprocessor directives, unless they are
  349.                  * recognised as comments.
  350.                  */
  351.                 if (lead_len == 0 && ptr[0] == '#')
  352.                 {
  353.                     int was_backslashed = FALSE;
  354.  
  355.                     while ((ptr[0] == '#' || was_backslashed) &&
  356.                          curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  357.                     {
  358.                         if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
  359.                             was_backslashed = TRUE;
  360.                         else
  361.                             was_backslashed = FALSE;
  362.                         ptr = ml_get(++curwin->w_cursor.lnum);
  363.                     }
  364.                     if (was_backslashed)
  365.                         newindent = 0;        /* Got to end of file */
  366.                     else
  367.                         newindent = get_indent();
  368.                 }
  369.                 p = skipwhite(ptr);
  370.                 if (*p == '}')        /* if line starts with '}': do indent */
  371.                     did_si = TRUE;
  372.                 else                /* can delete indent when '{' typed */
  373.                     can_si_back = TRUE;
  374.             }
  375.             curwin->w_cursor = old_cursor;
  376.         }
  377.         if (curbuf->b_p_si)
  378.             can_si = TRUE;
  379. #endif /* SMARTINDENT */
  380.  
  381.         did_ai = TRUE;
  382.     }
  383.     
  384.     /*
  385.      * Find out if the current line starts with a comment leader.
  386.      * This may then be inserted in front of the new line.
  387.      */
  388.     lead_len = get_leader_len(saved_line, &lead_flags);
  389.     if (lead_len > 0)
  390.     {
  391.         char_u    *lead_repl = NULL;            /* replaces comment leader */
  392.         int        lead_repl_len = 0;            /* length of *lead_repl */
  393.         char_u    lead_middle[COM_MAX_LEN];    /* middle-comment string */
  394.         char_u    lead_end[COM_MAX_LEN];        /* end-comment string */
  395.         char_u    *comment_end = NULL;        /* where lead_end has been found */
  396.         int        extra_space = FALSE;        /* append extra space */
  397.         int        current_flag;
  398.  
  399.         /*
  400.          * If the comment leader has the start, middle or end flag, it may not
  401.          * be used or may be replaced with the middle leader.
  402.          */
  403.         for (p = lead_flags; *p && *p != ':'; ++p)
  404.         {
  405.             if (*p == COM_START || *p == COM_MIDDLE)
  406.             {
  407.                 current_flag = *p;
  408.                 if (*p == COM_START)
  409.                 {
  410.                     /*
  411.                      * Doing "O" on a start of comment does not insert leader.
  412.                      */
  413.                     if (dir == BACKWARD)
  414.                     {
  415.                         lead_len = 0;
  416.                         break;
  417.                     }
  418.  
  419.                    /* find start of middle part */
  420.                     (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
  421.                 }
  422.  
  423.                 /*
  424.                  * Isolate the strings of the middle and end leader.
  425.                  */
  426.                 while (*p && p[-1] != ':')        /* find end of middle flags */
  427.                     ++p;
  428.                 (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
  429.                 while (*p && p[-1] != ':')        /* find end of end flags */
  430.                     ++p;
  431.                 (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
  432.  
  433.                 /*
  434.                  * If the end of the comment is in the same line, don't use
  435.                  * the comment leader.
  436.                  */
  437.                 if (dir == FORWARD)
  438.                 {
  439.                     n = STRLEN(lead_end);
  440.                     for (p = saved_line + lead_len; *p; ++p)
  441.                         if (STRNCMP(p, lead_end, n) == 0)
  442.                         {
  443.                             comment_end = p;
  444.                             lead_len = 0;
  445.                             break;
  446.                         }
  447.                 }
  448.  
  449.                 /*
  450.                  * Doing "o" on a start of comment inserts the middle leader.
  451.                  */
  452.                 if (lead_len)
  453.                 {
  454.                     if (current_flag == COM_START)
  455.                     {
  456.                         lead_repl = lead_middle;
  457.                         lead_repl_len = STRLEN(lead_middle);
  458.                     }
  459.  
  460.                     /*
  461.                      * If we have hit RETURN immediately after the start
  462.                      * comment leader, then put a space after the middle
  463.                      * comment leader on the next line.
  464.                      */
  465.                     if (!vim_iswhite(saved_line[lead_len - 1]) &&
  466.                             ((p_extra != NULL &&
  467.                                      (int)curwin->w_cursor.col == lead_len) ||
  468.                              (p_extra == NULL && saved_line[lead_len] == NUL)))
  469.                         extra_space = TRUE;
  470.                 }
  471.                 break;
  472.             }
  473.             if (*p == COM_END)
  474.             {
  475.                 /*
  476.                  * Doing "o" on the end of a comment does not insert leader.
  477.                  * Remember where the end is, might want to use it to find the
  478.                  * start (for C-comments).
  479.                  */
  480.                 if (dir == FORWARD)
  481.                 {
  482.                     comment_end = skipwhite(saved_line);
  483.                     lead_len = 0;
  484.                     break;
  485.                 }
  486.  
  487.                 /*
  488.                  * Doing "O" on the end of a comment inserts the middle leader.
  489.                  * Find the string for the middle leader, searching backwards.
  490.                  */
  491.                 while (p > curbuf->b_p_com && *p != ',')
  492.                     --p;
  493.                 for (lead_repl = p; lead_repl > curbuf->b_p_com &&
  494.                                             lead_repl[-1] != ':'; --lead_repl)
  495.                     ;
  496.                 lead_repl_len = p - lead_repl;
  497.                 break;
  498.             }
  499.             if (*p == COM_FIRST)
  500.             {
  501.                 /*
  502.                  * Comment leader for first line only:  Don't repeat leader
  503.                  * when using "O", blank out leader when using "o".
  504.                  */
  505.                 if (dir == BACKWARD)
  506.                     lead_len = 0;
  507.                 else
  508.                 {
  509.                     lead_repl = (char_u *)"";
  510.                     lead_repl_len = 0;
  511.                 }
  512.                 break;
  513.             }
  514.         }
  515.         if (lead_len)
  516.         {
  517.             /* allocate buffer (may concatenate p_exta later) */
  518.             leader = alloc(lead_len + lead_repl_len + extra_space +
  519.                                                               extra_len + 1);
  520.             allocated = leader;                /* remember to free it later */
  521.  
  522.             if (leader == NULL)
  523.                 lead_len = 0;
  524.             else
  525.             {
  526.                 STRNCPY(leader, saved_line, lead_len);
  527.                 leader[lead_len] = NUL;
  528.  
  529.                 /*
  530.                  * Replace leader with lead_repl, right or left adjusted
  531.                  */
  532.                 if (lead_repl != NULL)
  533.                 {
  534.                     for (p = lead_flags; *p && *p != ':'; ++p)
  535.                         if (*p == COM_RIGHT || *p == COM_LEFT)
  536.                             break;
  537.                     if (*p == COM_RIGHT)    /* right adjusted leader */
  538.                     {
  539.                         /* find last non-white in the leader to line up with */
  540.                         for (p = leader + lead_len - 1; p > leader &&
  541.                                                          vim_iswhite(*p); --p)
  542.                             ;
  543.  
  544.                         ++p;
  545.                         if (p < leader + lead_repl_len)
  546.                             p = leader;
  547.                         else
  548.                             p -= lead_repl_len;
  549.                         vim_memmove(p, lead_repl, (size_t)lead_repl_len);
  550.                         if (p + lead_repl_len > leader + lead_len)
  551.                             p[lead_repl_len] = NUL;
  552.  
  553.                         /* blank-out any other chars from the old leader. */
  554.                         while (--p >= leader)
  555.                             if (!vim_iswhite(*p))
  556.                                 *p = ' ';
  557.                     }
  558.                     else                     /* left adjusted leader */
  559.                     {
  560.                         p = skipwhite(leader);
  561.                         vim_memmove(p, lead_repl, (size_t)lead_repl_len);
  562.  
  563.                         /* blank-out any other chars from the old leader. */
  564.                         for (p += lead_repl_len; p < leader + lead_len; ++p)
  565.                             if (!vim_iswhite(*p))
  566.                                 *p = ' ';
  567.                         *p = NUL;
  568.                     }
  569.  
  570.                     /* Recompute the indent, it may have changed. */
  571.                     if (curbuf->b_p_ai
  572. #ifdef SMARTINDENT
  573.                                         || curbuf->b_p_si
  574. #endif
  575.                                                            )
  576.                         newindent = get_indent_str(leader);
  577.                 }
  578.  
  579.                 lead_len = STRLEN(leader);
  580.                 if (extra_space)
  581.                 {
  582.                     leader[lead_len++] = ' ';
  583.                     leader[lead_len] = NUL;
  584.                 }
  585.  
  586.                 newcol = lead_len;
  587.  
  588.                 /*
  589.                  * if a new indent will be set below, remove the indent that
  590.                  * is in the comment leader
  591.                  */
  592.                 if (newindent
  593. #ifdef SMARTINDENT
  594.                                 || did_si
  595. #endif
  596.                                            )
  597.                 {
  598.                     while (lead_len && vim_iswhite(*leader))
  599.                     {
  600.                         --lead_len;
  601.                         --newcol;
  602.                         ++leader;
  603.                     }
  604.                 }
  605.  
  606.             }
  607. #ifdef SMARTINDENT
  608.             did_si = can_si = FALSE;
  609. #endif
  610.         }
  611.         else if (comment_end != NULL)
  612.         {
  613.             /*
  614.              * We have finished a comment, so we don't use the leader.
  615.              * If this was a C-comment and 'ai' or 'si' is set do a normal
  616.              * indent to align with the line containing the start of the
  617.              * comment.
  618.              */
  619.             if (comment_end[0] == '*' && comment_end[1] == '/' &&
  620.                         (curbuf->b_p_ai
  621. #ifdef SMARTINDENT
  622.                                         || curbuf->b_p_si
  623. #endif
  624.                                                            ))
  625.             {
  626.                 old_cursor = curwin->w_cursor;
  627.                 curwin->w_cursor.col = comment_end - saved_line;
  628.                 if ((pos = findmatch(NUL)) != NULL)
  629.                 {
  630.                     curwin->w_cursor.lnum = pos->lnum;
  631.                     newindent = get_indent();
  632.                 }
  633.                 curwin->w_cursor = old_cursor;
  634.             }
  635.         }
  636.     }
  637.  
  638.     /* (State == INSERT || State == REPLACE), only when dir == FORWARD */
  639.     if (p_extra != NULL)
  640.     {
  641.         *p_extra = saved_char;            /* restore char that NUL replaced */
  642.  
  643.         /*
  644.          * When 'ai' set or "del_spaces" TRUE, skip to the first non-blank.
  645.          *
  646.          * When in REPLACE mode, put the deleted blanks on the replace
  647.          * stack, followed by a NUL, so they can be put back when
  648.          * a BS is entered.
  649.          */
  650.         if (State == REPLACE)
  651.             replace_push(NUL);        /* end of extra blanks */
  652.         if (curbuf->b_p_ai || del_spaces)
  653.         {
  654.             while (*p_extra == ' ' || *p_extra == '\t')
  655.             {
  656.                 if (State == REPLACE)
  657.                     replace_push(*p_extra);
  658.                 ++p_extra;
  659.             }
  660.         }
  661.         if (*p_extra != NUL)
  662.             did_ai = FALSE;         /* append some text, don't trucate now */
  663.     }
  664.  
  665.     if (p_extra == NULL)
  666.         p_extra = (char_u *)"";                /* append empty line */
  667.  
  668.     /* concatenate leader and p_extra, if there is a leader */
  669.     if (lead_len)
  670.     {
  671.         STRCAT(leader, p_extra);
  672.         p_extra = leader;
  673.     }
  674.  
  675.     old_cursor = curwin->w_cursor;
  676.     if (dir == BACKWARD)
  677.         --curwin->w_cursor.lnum;
  678.     if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_t)0, FALSE) == FAIL)
  679.         goto theend;
  680.     mark_adjust(curwin->w_cursor.lnum + 1, MAXLNUM, 1L, 0L);
  681.     if (newindent
  682. #ifdef SMARTINDENT
  683.                     || did_si
  684. #endif
  685.                                 )
  686.     {
  687.         ++curwin->w_cursor.lnum;
  688. #ifdef SMARTINDENT
  689.         if (did_si)
  690.         {
  691.             if (p_sr)
  692.                 newindent -= newindent % (int)curbuf->b_p_sw;
  693.             newindent += (int)curbuf->b_p_sw;
  694.         }
  695. #endif
  696.         set_indent(newindent, FALSE);
  697.         /*
  698.          * In REPLACE mode the new indent must be put on
  699.          * the replace stack for when it is deleted with BS
  700.          */
  701.         if (State == REPLACE)
  702.             for (n = 0; n < (int)curwin->w_cursor.col; ++n)
  703.                 replace_push(NUL);
  704.         newcol += curwin->w_cursor.col;
  705. #ifdef SMARTINDENT
  706.         if (no_si)
  707.             did_si = FALSE;
  708. #endif
  709.     }
  710.     /*
  711.      * In REPLACE mode the extra leader must be put on the replace stack for
  712.      * when it is deleted with BS.
  713.      */
  714.     if (State == REPLACE)
  715.         while (lead_len-- > 0)
  716.             replace_push(NUL);
  717.  
  718.     curwin->w_cursor = old_cursor;
  719.  
  720.     if (dir == FORWARD)
  721.     {
  722.         if (redraw)        /* want to know the old number of screen lines */
  723.         {
  724.             old_plines = plines(curwin->w_cursor.lnum);
  725.             new_plines = old_plines;
  726.         }
  727.         if (trunc_line || State == INSERT || State == REPLACE)
  728.         {
  729.             if (trunc_line)
  730.             {
  731.                     /* find start of trailing white space */
  732.                 for (n = STRLEN(saved_line); n > 0 &&
  733.                                           vim_iswhite(saved_line[n - 1]); --n)
  734.                     ;
  735.                 saved_line[n] = NUL;
  736.             }
  737.             else                    /* truncate current line at cursor */
  738.                 *(saved_line + curwin->w_cursor.col) = NUL;
  739.             ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
  740.             saved_line = NULL;
  741.             new_plines = plines(curwin->w_cursor.lnum);
  742.         }
  743.  
  744.         /*
  745.          * Get the cursor to the start of the line, so that 'curwin->w_row'
  746.          * gets set to the right physical line number for the stuff that
  747.          * follows...
  748.          */
  749.         curwin->w_cursor.col = 0;
  750.  
  751.         if (redraw)
  752.         {
  753.             /*
  754.              * Call cursupdate() to compute w_row.
  755.              * But we don't want it to update the srceen.
  756.              */
  757.             ++RedrawingDisabled;
  758.             cursupdate();
  759.             --RedrawingDisabled;
  760.  
  761.             /*
  762.              * If we're doing an open on the last logical line, then go ahead
  763.              * and scroll the screen up. Otherwise, just insert a blank line
  764.              * at the right place if the number of screen lines changed.
  765.              * We use calls to plines() in case the cursor is resting on a
  766.              * long line, we want to know the row below the line.
  767.              */
  768.             n = curwin->w_row + new_plines;
  769.             if (n == curwin->w_winpos + curwin->w_height)
  770.                 scrollup(1L);
  771.             else
  772.                 win_ins_lines(curwin, n,
  773.                   plines(curwin->w_cursor.lnum + 1) + new_plines - old_plines,
  774.                                                                   TRUE, TRUE);
  775.         }
  776.  
  777.         /*
  778.          * Put the cursor on the new line.  Careful: the cursupdate() and
  779.          * scrollup() above may have moved w_cursor, we must use old_cursor.
  780.          */
  781.         curwin->w_cursor.lnum = old_cursor.lnum + 1;
  782.     }
  783.     else if (redraw)             /* insert physical line above current line */
  784.         win_ins_lines(curwin, curwin->w_row, 1, TRUE, TRUE);
  785.  
  786.     curwin->w_cursor.col = newcol;
  787.  
  788. #ifdef LISPINDENT
  789.     /*
  790.      * May do lisp indenting.
  791.      */
  792.     if (leader == NULL && curbuf->b_p_lisp && curbuf->b_p_ai)
  793.         fixthisline(get_lisp_indent);
  794. #endif
  795. #ifdef CINDENT
  796.     /*
  797.      * May do indenting after opening a new line.
  798.      */
  799.     if (leader == NULL && curbuf->b_p_cin &&
  800.             in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW :
  801.                         KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
  802.         fixthisline(get_c_indent);
  803. #endif
  804.  
  805.     if (redraw)
  806.     {
  807.         updateScreen(VALID_TO_CURSCHAR);
  808.         cursupdate();            /* update curwin->w_row */
  809.     }
  810.     CHANGED;
  811.  
  812.     retval = TRUE;                /* success! */
  813. theend:
  814.     vim_free(saved_line);
  815.     vim_free(allocated);
  816.     return retval;
  817. }
  818.  
  819. /*
  820.  * get_leader_len() returns the length of the prefix of the given string
  821.  * which introduces a comment.  If this string is not a comment then 0 is
  822.  * returned.
  823.  * When "flags" is non-zero, it is set to point to the flags of the recognized
  824.  * comment leader.
  825.  */
  826.     int
  827. get_leader_len(line, flags)
  828.     char_u    *line;
  829.     char_u    **flags;
  830. {
  831.     int        i, j;
  832.     int        got_com = FALSE;
  833.     int        found_one;
  834.     char_u    part_buf[COM_MAX_LEN];    /* buffer for one option part */
  835.     char_u    *string;                /* pointer to comment string */
  836.     char_u    *list;
  837.  
  838.     if (!fo_do_comments)            /* don't format comments at all */
  839.         return 0;
  840.  
  841.     i = 0;
  842.     while (vim_iswhite(line[i]))    /* leading white space is ignored */
  843.         ++i;
  844.  
  845.     /*
  846.      * Repeat to match several nested comment strings.
  847.      */
  848.     while (line[i])
  849.     {
  850.         /*
  851.          * scan through the 'comments' option for a match
  852.          */
  853.         found_one = FALSE;
  854.         for (list = curbuf->b_p_com; *list; )
  855.         {
  856.             /*
  857.              * Get one option part into part_buf[].  Advance list to next one.
  858.              * put string at start of string.
  859.              */
  860.             if (!got_com && flags != NULL)    /* remember where flags started */
  861.                 *flags = list;
  862.             (void)copy_option_part(&list, part_buf, COM_MAX_LEN, ",");
  863.             string = vim_strchr(part_buf, ':');
  864.             if (string == NULL)        /* missing ':', ignore this part */
  865.                 continue;
  866.             *string++ = NUL;        /* isolate flags from string */
  867.  
  868.             /*
  869.              * When already found a nested comment, only accept further
  870.              * nested comments.
  871.              */
  872.             if (got_com && vim_strchr(part_buf, COM_NEST) == NULL)
  873.                 continue;
  874.  
  875.             /*
  876.              * Line contents and string must match.
  877.              */
  878.             for (j = 0; string[j] != NUL && string[j] == line[i + j]; ++j)
  879.                 ;
  880.             if (string[j] != NUL)
  881.                 continue;
  882.  
  883.             /*
  884.              * When 'b' flag used, there must be white space or an
  885.              * end-of-line after the string in the line.
  886.              */
  887.             if (vim_strchr(part_buf, COM_BLANK) != NULL &&
  888.                               !vim_iswhite(line[i + j]) && line[i + j] != NUL)
  889.                 continue;
  890.  
  891.             /*
  892.              * We have found a match, stop searching.
  893.              */
  894.             i += j;
  895.             got_com = TRUE;
  896.             found_one = TRUE;
  897.             break;
  898.         }
  899.  
  900.         /*
  901.          * No match found, stop scanning.
  902.          */
  903.         if (!found_one)
  904.             break;
  905.  
  906.         /*
  907.          * Include any trailing white space.
  908.          */
  909.         while (vim_iswhite(line[i]))
  910.             ++i;
  911.  
  912.         /*
  913.          * If this comment doesn't nest, stop here.
  914.          */
  915.         if (vim_strchr(part_buf, COM_NEST) == NULL)
  916.             break;
  917.     }
  918.     return (got_com ? i : 0);
  919. }
  920.  
  921. /*
  922.  * plines(p) - return the number of physical screen lines taken by line 'p'
  923.  */
  924.     int
  925. plines(p)
  926.     linenr_t    p;
  927. {
  928.     return plines_win(curwin, p);
  929. }
  930.     
  931.     int
  932. plines_win(wp, p)
  933.     WIN            *wp;
  934.     linenr_t    p;
  935. {
  936.     register long        col;
  937.     register char_u        *s;
  938.     register int        lines;
  939.  
  940.     if (!wp->w_p_wrap)
  941.         return 1;
  942.  
  943.     s = ml_get_buf(wp->w_buffer, p, FALSE);
  944.     if (*s == NUL)                /* empty line */
  945.         return 1;
  946.  
  947.     col = linetabsize(s);
  948.  
  949.     /*
  950.      * If list mode is on, then the '$' at the end of the line takes up one
  951.      * extra column.
  952.      */
  953.     if (wp->w_p_list)
  954.         col += 1;
  955.  
  956.     /*
  957.      * If 'number' mode is on, add another 8.
  958.      */
  959.     if (wp->w_p_nu)
  960.         col += 8;
  961.  
  962.     lines = (col + (Columns - 1)) / Columns;
  963.     if (lines <= wp->w_height)
  964.         return lines;
  965.     return (int)(wp->w_height);        /* maximum length */
  966. }
  967.  
  968. /*
  969.  * Count the physical lines (rows) for the lines "first" to "last" inclusive.
  970.  */
  971.     int
  972. plines_m(first, last)
  973.     linenr_t        first, last;
  974. {
  975.     return plines_m_win(curwin, first, last);
  976. }
  977.  
  978.     int
  979. plines_m_win(wp, first, last)
  980.     WIN                *wp;
  981.     linenr_t        first, last;
  982. {
  983.     int count = 0;
  984.  
  985.     while (first <= last)
  986.         count += plines_win(wp, first++);
  987.     return (count);
  988. }
  989.  
  990. /*
  991.  * Insert or replace a single character at the cursor position.
  992.  * When in REPLACE mode, replace any existing character.
  993.  */
  994.     void
  995. ins_char(c)
  996.     int            c;
  997. {
  998.     register char_u  *p;
  999.     char_u            *newp;
  1000.     char_u            *oldp;
  1001.     int                oldlen;
  1002.     int                extra;
  1003.     colnr_t            col = curwin->w_cursor.col;
  1004.     linenr_t        lnum = curwin->w_cursor.lnum;
  1005.  
  1006.     oldp = ml_get(lnum);
  1007.     oldlen = STRLEN(oldp) + 1;
  1008.  
  1009.     if (State != REPLACE || *(oldp + col) == NUL)
  1010.         extra = 1;
  1011.     else
  1012.         extra = 0;
  1013.  
  1014.     /*
  1015.      * a character has to be put on the replace stack if there is a
  1016.      * character that is replaced, so it can be put back when BS is used.
  1017.      * Otherwise a 0 is put on the stack, indicating that a new character
  1018.      * was inserted, which can be deleted when BS is used.
  1019.      */
  1020.     if (State == REPLACE)
  1021.         replace_push(!extra ? *(oldp + col) : 0);
  1022.     newp = alloc_check((unsigned)(oldlen + extra));
  1023.     if (newp == NULL)
  1024.         return;
  1025.     vim_memmove(newp, oldp, (size_t)col);
  1026.     p = newp + col;
  1027.     vim_memmove(p + extra, oldp + col, (size_t)(oldlen - col));
  1028.     *p = c;
  1029.     ml_replace(lnum, newp, FALSE);
  1030.  
  1031.     /*
  1032.      * If we're in insert or replace mode and 'showmatch' is set, then check for
  1033.      * right parens and braces. If there isn't a match, then beep. If there
  1034.      * is a match AND it's on the screen, then flash to it briefly. If it
  1035.      * isn't on the screen, don't do anything.
  1036.      */
  1037. #ifdef RIGHTLEFT
  1038.     if (p_sm && (State & INSERT) && 
  1039.             ((!curwin->w_p_rl && (c == ')' || c == '}' || c == ']')) ||
  1040.              (curwin->w_p_rl && (c == '(' || c == '{' || c == '['))))
  1041. #else
  1042.      if (p_sm && (State & INSERT) && (c == ')' || c == '}' || c == ']'))
  1043. #endif
  1044.         showmatch();
  1045.  
  1046. #ifdef RIGHTLEFT
  1047.     if (!p_ri || State == REPLACE)        /* normal insert: cursor right */
  1048. #endif
  1049.         ++curwin->w_cursor.col;
  1050.     CHANGED;
  1051. }
  1052.  
  1053. /*
  1054.  * Insert a string at the cursor position.
  1055.  * Note: Nothing special for replace mode.
  1056.  */
  1057.     void
  1058. ins_str(s)
  1059.     char_u  *s;
  1060. {
  1061.     register char_u        *oldp, *newp;
  1062.     register int        newlen = STRLEN(s);
  1063.     int                    oldlen;
  1064.     colnr_t                col = curwin->w_cursor.col;
  1065.     linenr_t            lnum = curwin->w_cursor.lnum;
  1066.  
  1067.     oldp = ml_get(lnum);
  1068.     oldlen = STRLEN(oldp);
  1069.  
  1070.     newp = alloc_check((unsigned)(oldlen + newlen + 1));
  1071.     if (newp == NULL)
  1072.         return;
  1073.     vim_memmove(newp, oldp, (size_t)col);
  1074.     vim_memmove(newp + col, s, (size_t)newlen);
  1075.     vim_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
  1076.     ml_replace(lnum, newp, FALSE);
  1077.     curwin->w_cursor.col += newlen;
  1078.     CHANGED;
  1079. }
  1080.  
  1081. /*
  1082.  * delete one character under the cursor
  1083.  *
  1084.  * return FAIL for failure, OK otherwise
  1085.  */
  1086.     int
  1087. delchar(fixpos)
  1088.     int            fixpos;     /* if TRUE fix the cursor position when done */
  1089. {
  1090.     char_u        *oldp, *newp;
  1091.     colnr_t        oldlen;
  1092.     linenr_t    lnum = curwin->w_cursor.lnum;
  1093.     colnr_t        col = curwin->w_cursor.col;
  1094.     int            was_alloced;
  1095.  
  1096.     oldp = ml_get(lnum);
  1097.     oldlen = STRLEN(oldp);
  1098.  
  1099.     if (col >= oldlen)    /* can't do anything (happens with replace mode) */
  1100.         return FAIL;
  1101.  
  1102. /*
  1103.  * If the old line has been allocated the deletion can be done in the
  1104.  * existing line. Otherwise a new line has to be allocated
  1105.  */
  1106.     was_alloced = ml_line_alloced();        /* check if oldp was allocated */
  1107.     if (was_alloced)
  1108.         newp = oldp;                            /* use same allocated memory */
  1109.     else
  1110.     {
  1111.         newp = alloc((unsigned)oldlen);        /* need to allocated a new line */
  1112.         if (newp == NULL)
  1113.             return FAIL;
  1114.         vim_memmove(newp, oldp, (size_t)col);
  1115.     }
  1116.     vim_memmove(newp + col, oldp + col + 1, (size_t)(oldlen - col));
  1117.     if (!was_alloced)
  1118.         ml_replace(lnum, newp, FALSE);
  1119.  
  1120.     /*
  1121.      * If we just took off the last character of a non-blank line, we don't
  1122.      * want to end up positioned at the NUL.
  1123.      */
  1124.     if (fixpos && curwin->w_cursor.col > 0 && col == oldlen - 1)
  1125.         --curwin->w_cursor.col;
  1126.  
  1127.     CHANGED;
  1128.     return OK;
  1129. }
  1130.  
  1131. /*
  1132.  * Delete from cursor to end of line.
  1133.  *
  1134.  * return FAIL for failure, OK otherwise
  1135.  */
  1136.     int
  1137. truncate_line(fixpos)
  1138.     int            fixpos;     /* if TRUE fix the cursor position when done */
  1139. {
  1140.     char_u        *newp;
  1141.     linenr_t    lnum = curwin->w_cursor.lnum;
  1142.     colnr_t        col = curwin->w_cursor.col;
  1143.  
  1144.     if (col == 0)
  1145.         newp = strsave((char_u *)"");
  1146.     else
  1147.         newp = strnsave(ml_get(lnum), col);
  1148.  
  1149.     if (newp == NULL)
  1150.         return FAIL;
  1151.  
  1152.     ml_replace(lnum, newp, FALSE);
  1153.  
  1154.     /*
  1155.      * If "fixpos" is TRUE we don't want to end up positioned at the NUL.
  1156.      */
  1157.     if (fixpos && curwin->w_cursor.col > 0)
  1158.         --curwin->w_cursor.col;
  1159.  
  1160.     CHANGED;
  1161.     return OK;
  1162. }
  1163.  
  1164.     void
  1165. dellines(nlines, dowindow, undo)
  1166.     long             nlines;            /* number of lines to delete */
  1167.     int             dowindow;        /* if true, update the window */
  1168.     int                undo;            /* if true, prepare for undo */
  1169. {
  1170.     int             num_plines = 0;
  1171.  
  1172.     if (nlines <= 0)
  1173.         return;
  1174.     /*
  1175.      * There's no point in keeping the window updated if redrawing is disabled
  1176.      * or we're deleting more than a window's worth of lines.
  1177.      */
  1178.     if (RedrawingDisabled)
  1179.         dowindow = FALSE;
  1180.     else if (nlines > (curwin->w_height - curwin->w_row) && dowindow)
  1181.     {
  1182.         dowindow = FALSE;
  1183.         /* flaky way to clear rest of window */
  1184.         win_del_lines(curwin, curwin->w_row, curwin->w_height, TRUE, TRUE);
  1185.     }
  1186.     /* save the deleted lines for undo */
  1187.     if (undo && u_savedel(curwin->w_cursor.lnum, nlines) == FAIL)
  1188.         return;
  1189.  
  1190.     /* adjust marks for deleted lines and lines that follow */
  1191.     mark_adjust(curwin->w_cursor.lnum, curwin->w_cursor.lnum + nlines - 1,
  1192.                                                             MAXLNUM, -nlines);
  1193.  
  1194.     while (nlines-- > 0)
  1195.     {
  1196.         if (curbuf->b_ml.ml_flags & ML_EMPTY)         /* nothing to delete */
  1197.             break;
  1198.  
  1199.         /*
  1200.          * Set up to delete the correct number of physical lines on the
  1201.          * window
  1202.          */
  1203.         if (dowindow)
  1204.             num_plines += plines(curwin->w_cursor.lnum);
  1205.  
  1206.         ml_delete(curwin->w_cursor.lnum, TRUE);
  1207.  
  1208.         CHANGED;
  1209.  
  1210.         /* If we delete the last line in the file, stop */
  1211.         if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  1212.         {
  1213.             curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1214.             break;
  1215.         }
  1216.     }
  1217.     curwin->w_cursor.col = 0;
  1218.     /*
  1219.      * Delete the correct number of physical lines on the window
  1220.      */
  1221.     if (dowindow && num_plines > 0)
  1222.         win_del_lines(curwin, curwin->w_row, num_plines, TRUE, TRUE);
  1223. }
  1224.  
  1225.     int
  1226. gchar(pos)
  1227.     FPOS *pos;
  1228. {
  1229.     return (int)(*(ml_get_pos(pos)));
  1230. }
  1231.  
  1232.     int
  1233. gchar_cursor()
  1234. {
  1235.     return (int)(*(ml_get_cursor()));
  1236. }
  1237.  
  1238. /*
  1239.  * Write a character at the current cursor position.
  1240.  * It is directly written into the block.
  1241.  */
  1242.     void
  1243. pchar_cursor(c)
  1244.     int c;
  1245. {
  1246.     *(ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE) +
  1247.                                                     curwin->w_cursor.col) = c;
  1248. }
  1249.  
  1250. /*
  1251.  * Put *pos at end of current buffer
  1252.  */
  1253.     void
  1254. goto_endofbuf(pos)
  1255.     FPOS    *pos;
  1256. {
  1257.     char_u    *p;
  1258.  
  1259.     pos->lnum = curbuf->b_ml.ml_line_count;
  1260.     pos->col = 0;
  1261.     p = ml_get(pos->lnum);
  1262.     while (*p++)
  1263.         ++pos->col;
  1264. }
  1265.  
  1266. /*
  1267.  * When extra == 0: Return TRUE if the cursor is before or on the first
  1268.  *                    non-blank in the line.
  1269.  * When extra == 1: Return TRUE if the cursor is before the first non-blank in
  1270.  *                    the line.
  1271.  */
  1272.     int
  1273. inindent(extra)
  1274.     int        extra;
  1275. {
  1276.     register char_u *ptr;
  1277.     register colnr_t col;
  1278.  
  1279.     for (col = 0, ptr = ml_get_curline(); vim_iswhite(*ptr); ++col)
  1280.         ++ptr;
  1281.     if (col >= curwin->w_cursor.col + extra)
  1282.         return TRUE;
  1283.     else
  1284.         return FALSE;
  1285. }
  1286.  
  1287. /*
  1288.  * skipwhite: skip over ' ' and '\t'.
  1289.  */
  1290.     char_u *
  1291. skipwhite(p)
  1292.     register char_u *p;
  1293. {
  1294.     while (vim_iswhite(*p))    /* skip to next non-white */
  1295.         ++p;
  1296.     return p;
  1297. }
  1298.  
  1299. /*
  1300.  * skipdigits: skip over digits;
  1301.  */
  1302.     char_u *
  1303. skipdigits(p)
  1304.     register char_u *p;
  1305. {
  1306.     while (isdigit(*p))    /* skip to next non-digit */
  1307.         ++p;
  1308.     return p;
  1309. }
  1310.  
  1311. /*
  1312.  * skiptowhite: skip over text until ' ' or '\t' or NUL.
  1313.  */
  1314.     char_u *
  1315. skiptowhite(p)
  1316.     register char_u *p;
  1317. {
  1318.     while (*p != ' ' && *p != '\t' && *p != NUL)
  1319.         ++p;
  1320.     return p;
  1321. }
  1322.  
  1323. /*
  1324.  * skiptowhite_esc: Like skiptowhite(), but also skip escaped chars
  1325.  */
  1326.     char_u *
  1327. skiptowhite_esc(p)
  1328.     register char_u *p;
  1329. {
  1330.     while (*p != ' ' && *p != '\t' && *p != NUL)
  1331.     {
  1332.         if ((*p == '\\' || *p == Ctrl('V')) && *(p + 1) != NUL)
  1333.             ++p;
  1334.         ++p;
  1335.     }
  1336.     return p;
  1337. }
  1338.  
  1339. /*
  1340.  * getdigits: get a number from a string and skip over it
  1341.  *
  1342.  * note: you must give a pointer to a char_u pointer!
  1343.  */
  1344.  
  1345.     long
  1346. getdigits(pp)
  1347.     char_u **pp;
  1348. {
  1349.     register char_u *p;
  1350.     long retval;
  1351.     
  1352.     p = *pp;
  1353.     retval = atol((char *)p);
  1354.     p = skipdigits(p);        /* skip to next non-digit */
  1355.     *pp = p;
  1356.     return retval;
  1357. }
  1358.  
  1359. /*
  1360.  * Skip to next part of an option argument: Skip space and comma.
  1361.  */
  1362.     char_u *
  1363. skip_to_option_part(p)
  1364.     char_u    *p;
  1365. {
  1366.     if (*p == ',')
  1367.         ++p;
  1368.     while (*p == ' ')
  1369.         ++p;
  1370.     return p;
  1371. }
  1372.  
  1373.     char *
  1374. plural(n)
  1375.     long n;
  1376. {
  1377.     static char buf[2] = "s";
  1378.  
  1379.     if (n == 1)
  1380.         return &(buf[1]);
  1381.     return &(buf[0]);
  1382. }
  1383.  
  1384. /*
  1385.  * set_Changed is called when something in the current buffer is changed
  1386.  */
  1387.     void
  1388. set_Changed()
  1389. {
  1390.     if (!curbuf->b_changed)
  1391.     {
  1392.         change_warning();
  1393.         curbuf->b_changed = TRUE;
  1394.         check_status(curbuf);
  1395.     }
  1396.     modified = TRUE;                /* used for redrawing */
  1397. }
  1398.  
  1399. /*
  1400.  * unset_Changed is called when the changed flag must be reset for buffer 'buf'
  1401.  */
  1402.     void
  1403. unset_Changed(buf)
  1404.     BUF        *buf;
  1405. {
  1406.     if (buf->b_changed)
  1407.     {
  1408.         buf->b_changed = 0;
  1409.         check_status(buf);
  1410.     }
  1411. }
  1412.  
  1413. /*
  1414.  * check_status: called when the status bars for the buffer 'buf'
  1415.  *                 need to be updated
  1416.  */
  1417.     static void
  1418. check_status(buf)
  1419.     BUF        *buf;
  1420. {
  1421.     WIN        *wp;
  1422.     int        i;
  1423.  
  1424.     i = 0;
  1425.     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  1426.         if (wp->w_buffer == buf && wp->w_status_height)
  1427.         {
  1428.             wp->w_redr_status = TRUE;
  1429.             ++i;
  1430.         }
  1431.     if (i)
  1432.         redraw_later(NOT_VALID);
  1433. }
  1434.  
  1435. /*
  1436.  * If the file is readonly, give a warning message with the first change.
  1437.  * Don't do this for autocommands.
  1438.  * Don't use emsg(), because it flushes the macro buffer.
  1439.  * If we have undone all changes b_changed will be FALSE, but b_did_warn
  1440.  * will be TRUE.
  1441.  */
  1442.     void
  1443. change_warning()
  1444. {
  1445.     if (curbuf->b_did_warn == FALSE && curbuf->b_changed == 0 &&
  1446. #ifdef AUTOCMD
  1447.                                               !autocmd_busy &&
  1448. #endif
  1449.                                               curbuf->b_p_ro)
  1450.     {
  1451.         curbuf->b_did_warn = TRUE;
  1452.         MSG("Warning: Changing a readonly file");
  1453.         mch_delay(1000L, TRUE);    /* give him some time to think about it */
  1454.     }
  1455. }
  1456.  
  1457. /*
  1458.  * Ask for a reply from the user, a 'y' or a 'n'.
  1459.  * No other characters are accepted, the message is repeated until a valid
  1460.  * reply is entered or CTRL-C is hit.
  1461.  * If direct is TRUE, don't use vgetc but mch_inchar, don't get characters from
  1462.  * any buffers but directly from the user.
  1463.  *
  1464.  * return the 'y' or 'n'
  1465.  */
  1466.     int
  1467. ask_yesno(str, direct)
  1468.     char_u    *str;
  1469.     int        direct;
  1470. {
  1471.     int        r = ' ';
  1472.     char_u    buf[20];
  1473.     int        len = 0;
  1474.     int        idx = 0;
  1475.  
  1476.     if (exiting)                /* put terminal in raw mode for this question */
  1477.         settmode(1);
  1478.     while (r != 'y' && r != 'n')
  1479.     {
  1480.         (void)set_highlight('r');    /* same highlighting as for wait_return */
  1481.         msg_highlight = TRUE;
  1482.         smsg((char_u *)"%s (y/n)?", str);
  1483.         if (direct)
  1484.         {
  1485.             flushbuf();
  1486.             if (idx >= len)
  1487.             {
  1488.                 len = mch_inchar(buf, 20, -1L);
  1489.                 idx = 0;
  1490.             }
  1491.             r = buf[idx++];
  1492.         }
  1493.         else
  1494.             r = vgetc();
  1495.         if (r == Ctrl('C') || r == ESC)
  1496.             r = 'n';
  1497.         msg_outchar(r);        /* show what you typed */
  1498.         flushbuf();
  1499.     }
  1500.     return r;
  1501. }
  1502.  
  1503. /*
  1504.  * get a number from the user
  1505.  */
  1506.     int
  1507. get_number()
  1508. {
  1509.     int        n = 0;
  1510.     int        c;
  1511.  
  1512.     for (;;)
  1513.     {
  1514.         windgoto(msg_row, msg_col);
  1515.         c = vgetc();
  1516.         if (isdigit(c))
  1517.         {
  1518.             n = n * 10 + c - '0';
  1519.             msg_outchar(c);
  1520.         }
  1521.         else if (c == K_DEL || c == K_BS || c == Ctrl('H'))
  1522.         {
  1523.             n /= 10;
  1524.             MSG_OUTSTR("\b \b");
  1525.         }
  1526.         else if (c == CR || c == NL || c == Ctrl('C'))
  1527.             break;
  1528.     }
  1529.     return n;
  1530. }
  1531.  
  1532.     void
  1533. msgmore(n)
  1534.     long n;
  1535. {
  1536.     long pn;
  1537.  
  1538.     if (global_busy ||        /* no messages now, wait until global is finished */
  1539.             keep_msg)        /* there is a message already, skip this one */
  1540.         return;
  1541.  
  1542.     if (n > 0)
  1543.         pn = n;
  1544.     else
  1545.         pn = -n;
  1546.  
  1547.     if (pn > p_report)
  1548.     {
  1549.         sprintf((char *)msg_buf, "%ld %s line%s %s",
  1550.                 pn, n > 0 ? "more" : "fewer", plural(pn),
  1551.                 got_int ? "(Interrupted)" : "");
  1552.         if (msg(msg_buf))
  1553.             keep_msg = msg_buf;
  1554.     }
  1555. }
  1556.  
  1557. /*
  1558.  * flush map and typeahead buffers and give a warning for an error
  1559.  */
  1560.     void
  1561. beep_flush()
  1562. {
  1563.     flush_buffers(FALSE);
  1564.     vim_beep();
  1565. }
  1566.  
  1567. /*
  1568.  * give a warning for an error
  1569.  */
  1570.     void
  1571. vim_beep()
  1572. {
  1573.     if (p_vb)
  1574.     {
  1575. #ifdef DJGPP
  1576.         ScreenVisualBell();
  1577. #else
  1578.         outstr(T_VB);
  1579. #endif
  1580.     }
  1581.     else
  1582.     {
  1583. #if defined MSDOS  ||  defined WIN32 /* ? gvr */
  1584.         /*
  1585.          * The number of beeps outputted is reduced to avoid having to wait
  1586.          * for all the beeps to finish. This is only a problem on systems
  1587.          * where the beeps don't overlap.
  1588.          */
  1589.         if (beep_count == 0 || beep_count == 10)
  1590.         {
  1591.             outchar('\007');
  1592.             beep_count = 1;
  1593.         }
  1594.         else
  1595.             ++beep_count;
  1596. #else
  1597.         outchar('\007');
  1598. #endif
  1599.     }
  1600. }
  1601.  
  1602. /*
  1603.  * To get the "real" home directory:
  1604.  * - get value of $HOME
  1605.  * For Unix:
  1606.  *    - go to that directory
  1607.  *    - do mch_dirname() to get the real name of that directory.
  1608.  *    This also works with mounts and links.
  1609.  *    Don't do this for MS-DOS, it will change the "current dir" for a drive.
  1610.  */
  1611. static char_u    *homedir = NULL;
  1612.  
  1613.     void
  1614. init_homedir()
  1615. {
  1616.     char_u    *var;
  1617.  
  1618.     var = vim_getenv((char_u *)"HOME");
  1619. #if defined(OS2) || defined(MSDOS) || defined(WIN32)
  1620.     /*
  1621.      * Default home dir is C:/
  1622.      * Best assumption we can make in such a situation.
  1623.      */
  1624.     if (var == NULL)
  1625.         var = "C:/";
  1626. #endif
  1627.     if (var != NULL)
  1628.     {
  1629. #ifdef UNIX
  1630.         if (mch_dirname(NameBuff, MAXPATHL) == OK)
  1631.         {
  1632.             if (!vim_chdir((char *)var) && mch_dirname(IObuff, IOSIZE) == OK)
  1633.                 var = IObuff;
  1634.             vim_chdir((char *)NameBuff);
  1635.         }
  1636. #endif
  1637.         homedir = strsave(var);
  1638.     }
  1639. }
  1640.  
  1641. /* 
  1642.  * Expand environment variable with path name.
  1643.  * For Unix and OS/2 "~/" is also expanded, like $HOME.
  1644.  * If anything fails no expansion is done and dst equals src.
  1645.  * Note that IObuff must NOT be used as either src or dst!  This is because
  1646.  * vim_getenv() may use IObuff to do its expansion.
  1647.  */
  1648.     void
  1649. expand_env(src, dst, dstlen)
  1650.     char_u    *src;            /* input string e.g. "$HOME/vim.hlp" */
  1651.     char_u    *dst;            /* where to put the result */
  1652.     int        dstlen;            /* maximum length of the result */
  1653. {
  1654.     char_u    *tail;
  1655.     int        c;
  1656.     char_u    *var;
  1657.     int        copy_char;
  1658. #if defined(UNIX) || defined(OS2)
  1659.     int        mustfree;
  1660.     int        at_start = TRUE;
  1661. #endif
  1662.  
  1663.     src = skipwhite(src);
  1664.     --dstlen;                /* leave one char space for "\," */
  1665.     while (*src && dstlen > 0)
  1666.     {
  1667.         copy_char = TRUE;
  1668.         if (*src == '$'
  1669. #if defined(UNIX) || defined(OS2)
  1670.                         || (*src == '~' && at_start)
  1671. #endif
  1672.                                                     )
  1673.         {
  1674. #if defined(UNIX) || defined(OS2)
  1675.             mustfree = FALSE;
  1676.  
  1677.             /*
  1678.              * The variable name is copied into dst temporarily, because it may
  1679.              * be a string in read-only memory and a NUL needs to be inserted.
  1680.              */
  1681.             if (*src == '$')                            /* environment var */
  1682.             {
  1683. #endif
  1684.                 tail = src + 1;
  1685.                 var = dst;
  1686.                 c = dstlen - 1;
  1687.                 while (c-- > 0 && *tail && isidchar(*tail))
  1688. #ifdef OS2
  1689.                 {    /* env vars only in uppercase */
  1690.                     *var++ = toupper(*tail);    /* toupper() may be a macro! */
  1691.                     tail++;
  1692.                 }
  1693. #else
  1694.                     *var++ = *tail++;
  1695. #endif
  1696.                 *var = NUL;
  1697. #if defined(OS2) || defined(MSDOS) || defined(WIN32)
  1698.                 /* use "C:/" when $HOME is not set */
  1699.                 if (STRCMP(dst, "HOME") == 0)
  1700.                     var = homedir;
  1701.                 else
  1702. #endif
  1703.                     var = vim_getenv(dst);
  1704. #if defined(UNIX) || defined(OS2)
  1705.             }
  1706.                                                         /* home directory */
  1707.             else if (src[1] == NUL ||
  1708.                               vim_strchr((char_u *)"/ ,\t\n", src[1]) != NULL)
  1709.             {
  1710.                 var = homedir;
  1711.                 tail = src + 1;
  1712.             }
  1713.             else                                        /* user directory */
  1714. # ifdef OS2
  1715.             {
  1716.                 /* cannot expand user's home directory, so don't try */
  1717.                 var = NULL;
  1718.                 tail = "";    /* shut gcc up about "may be used uninitialized" */
  1719.             }
  1720. # else
  1721.             {
  1722.                 /*
  1723.                  * Copy ~user to dst[], so we can put a NUL after it.
  1724.                  */
  1725.                 tail = src;
  1726.                 var = dst;
  1727.                 c = dstlen - 1;
  1728.                 while (c-- > 0 && *tail &&
  1729.                                        isfilechar(*tail) && !ispathsep(*tail))
  1730.                     *var++ = *tail++;
  1731.                 *var = NUL;
  1732.  
  1733.                 /*
  1734.                  * If the system supports getpwnam(), use it.
  1735.                  * Otherwise, or if getpwnam() fails, the shell is used to
  1736.                  * expand ~user.  This is slower and may fail if the shell
  1737.                  * does not support ~user (old versions of /bin/sh).
  1738.                  */
  1739. #  if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
  1740.                 {
  1741.                     struct passwd *pw;
  1742.  
  1743.                     pw = getpwnam((char *)dst + 1);
  1744.                     if (pw != NULL)
  1745.                         var = (char_u *)pw->pw_dir;
  1746.                     else
  1747.                         var = NULL;
  1748.                 }
  1749.                 if (var == NULL)
  1750. #  endif
  1751.                 {
  1752.                     var = ExpandOne(dst, NULL, 0, WILD_EXPAND_FREE);
  1753.                     mustfree = TRUE;
  1754.                 }
  1755.             }
  1756. # endif /* OS2 */
  1757. #endif /* UNIX || OS2 */
  1758.             if (var != NULL && *var != NUL &&
  1759.                           (STRLEN(var) + STRLEN(tail) + 1 < (unsigned)dstlen))
  1760.             {
  1761.                 STRCPY(dst, var);
  1762.                 dstlen -= STRLEN(var);
  1763.                 dst += STRLEN(var);
  1764.                     /* if var[] ends in a path separator and tail[] starts
  1765.                      * with it, skip a character */
  1766.                 if (*var && ispathsep(*(dst-1)) && ispathsep(*tail))
  1767.                     ++tail;
  1768.                 src = tail;
  1769.                 copy_char = FALSE;
  1770.             }
  1771. #if defined(UNIX) || defined(OS2)
  1772.             if (mustfree)
  1773.                 vim_free(var);
  1774. #endif
  1775.         }
  1776.  
  1777.         if (copy_char)        /* copy at least one char */
  1778.         {
  1779. #if defined(UNIX) || defined(OS2)
  1780.             /*
  1781.              * Recogize the start of a new name, for '~'.
  1782.              */
  1783.             at_start = FALSE;
  1784. #endif
  1785.             if (src[0] == '\\')
  1786.             {
  1787.                 *dst++ = *src++;
  1788.                 --dstlen;
  1789.             }
  1790. #if defined(UNIX) || defined(OS2)
  1791.             else if (src[0] == ' ' || src[0] == ',')
  1792.                 at_start = TRUE;
  1793. #endif
  1794.             *dst++ = *src++;
  1795.             --dstlen;
  1796.         }
  1797.     }
  1798.     *dst = NUL;
  1799. }
  1800.  
  1801. /* 
  1802.  * Replace home directory by "~/" in each space or comma separated filename in
  1803.  * 'src'. If anything fails (except when out of space) dst equals src.
  1804.  */
  1805.     void
  1806. home_replace(buf, src, dst, dstlen)
  1807.     BUF        *buf;            /* when not NULL, check for help files */
  1808.     char_u    *src;            /* input file name */
  1809.     char_u    *dst;            /* where to put the result */
  1810.     int        dstlen;            /* maximum length of the result */
  1811. {
  1812.     size_t    dirlen = 0, envlen = 0;
  1813.     size_t    len;
  1814.     char_u    *homedir_env;
  1815.     char_u    *p;
  1816.  
  1817.     if (src == NULL)
  1818.     {
  1819.         *dst = NUL;
  1820.         return;
  1821.     }
  1822.  
  1823.     /*
  1824.      * If the file is a help file, remove the path completely.
  1825.      */
  1826.     if (buf != NULL && buf->b_help)
  1827.     {
  1828.         STRCPY(dst, gettail(src));
  1829.         return;
  1830.     }
  1831.  
  1832.     /*
  1833.      * We check both the value of the $HOME environment variable and the
  1834.      * "real" home directory.
  1835.      */
  1836.     if (homedir != NULL)
  1837.         dirlen = STRLEN(homedir);
  1838.     homedir_env = vim_getenv((char_u *)"HOME");
  1839.     if (homedir_env != NULL)
  1840.         envlen = STRLEN(homedir_env);
  1841.  
  1842.     src = skipwhite(src);
  1843.     while (*src && dstlen > 0)
  1844.     {
  1845.         /*
  1846.          * Here we are at the beginning of a filename.
  1847.          * First, check to see if the beginning of the filename matches
  1848.          * $HOME or the "real" home directory. Check that there is a '/'
  1849.          * after the match (so that if e.g. the file is "/home/pieter/bla",
  1850.          * and the home directory is "/home/piet", the file does not end up
  1851.          * as "~er/bla" (which would seem to indicate the file "bla" in user
  1852.          * er's home directory)).
  1853.          */
  1854.         p = homedir;
  1855.         len = dirlen;
  1856.         for (;;)
  1857.         {
  1858.             if (len && fnamencmp(src, p, len) == 0 && (ispathsep(src[len]) ||
  1859.                        src[len] == ',' || src[len] == ' ' || src[len] == NUL))
  1860.             {
  1861.                 src += len;
  1862.                 if (--dstlen > 0)
  1863.                     *dst++ = '~';
  1864.                 /*
  1865.                  * If it's just the home directory, make it "~/".
  1866.                  */
  1867.                 if (!ispathsep(src[0]) && --dstlen > 0)
  1868.                     *dst++ = '/';
  1869.             }
  1870.             if (p == homedir_env)
  1871.                 break;
  1872.             p = homedir_env;
  1873.             len = envlen;
  1874.         }
  1875.  
  1876.         /* skip to separator: space or comma */
  1877.         while (*src && *src != ',' && *src != ' ' && --dstlen > 0)
  1878.             *dst++ = *src++;
  1879.         /* skip separator */
  1880.         while ((*src == ' ' || *src == ',') && --dstlen > 0)
  1881.             *dst++ = *src++;
  1882.     }
  1883.     /* if (dstlen == 0) out of space, what to do??? */
  1884.  
  1885.     *dst = NUL;
  1886. }
  1887.  
  1888. /*
  1889.  * Like home_replace, store the replaced string in allocated memory.
  1890.  * When something fails, NULL is returned.
  1891.  */
  1892.     char_u    *
  1893. home_replace_save(buf, src)
  1894.     BUF        *buf;            /* when not NULL, check for help files */
  1895.     char_u    *src;            /* input file name */
  1896. {
  1897.     char_u        *dst;
  1898.     unsigned    len;
  1899.  
  1900.     if (src == NULL)        /* just in case */
  1901.         len = 3;
  1902.     else
  1903.         len = STRLEN(src) + 3;        /* extra space for "~/" and trailing NUL */
  1904.     dst = alloc(len);
  1905.     if (dst != NULL)
  1906.         home_replace(buf, src, dst, len);
  1907.     return dst;
  1908. }
  1909.  
  1910. /*
  1911.  * Compare two file names and return:
  1912.  * FPC_SAME   if they both exist and are the same file.
  1913.  * FPC_DIFF   if they both exist and are different files.
  1914.  * FPC_NOTX   if they both don't exist.
  1915.  * FPC_DIFFX  if one of them doesn't exist.
  1916.  * For the first name environment variables are expanded
  1917.  */
  1918.     int
  1919. fullpathcmp(s1, s2)
  1920.     char_u *s1, *s2;
  1921. {
  1922. #ifdef UNIX
  1923.     char_u            buf1[MAXPATHL];
  1924.     struct stat        st1, st2;
  1925.     int                r1, r2;
  1926.  
  1927.     expand_env(s1, buf1, MAXPATHL);
  1928.     r1 = stat((char *)buf1, &st1);
  1929.     r2 = stat((char *)s2, &st2);
  1930.     if (r1 != 0 && r2 != 0)
  1931.         return FPC_NOTX;
  1932.     if (r1 != 0 || r2 != 0)
  1933.         return FPC_DIFFX;
  1934.     if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
  1935.         return FPC_SAME;
  1936.     return FPC_DIFF;
  1937. #else
  1938.     char_u    *buf1 = NULL;
  1939.     char_u    *buf2 = NULL;
  1940.     int        retval = FPC_DIFF;
  1941.     int        r1, r2;
  1942.     
  1943.     if ((buf1 = alloc(MAXPATHL)) != NULL && (buf2 = alloc(MAXPATHL)) != NULL)
  1944.     {
  1945.         expand_env(s1, buf2, MAXPATHL);
  1946.         /*
  1947.          * If FullName() failed, the file probably doesn't exist.
  1948.          */
  1949.         r1 = FullName(buf2, buf1, MAXPATHL, FALSE);
  1950.         r2 = FullName(s2, buf2, MAXPATHL, FALSE);
  1951.         if (r1 != OK && r2 != OK)
  1952.             retval = FPC_NOTX;
  1953.         else if (r1 != OK || r2 != OK)
  1954.             retval = FPC_DIFFX;
  1955.         else if (fnamecmp(buf1, buf2))
  1956.             retval = FPC_DIFF;
  1957.         else
  1958.             retval = FPC_SAME;
  1959.     }
  1960.     vim_free(buf1);
  1961.     vim_free(buf2);
  1962.     return retval;
  1963. #endif
  1964. }
  1965.  
  1966. /*
  1967.  * get the tail of a path: the file name.
  1968.  */
  1969.     char_u *
  1970. gettail(fname)
  1971.     char_u *fname;
  1972. {
  1973.     register char_u *p1, *p2;
  1974.  
  1975.     if (fname == NULL)
  1976.         return (char_u *)"";
  1977.     for (p1 = p2 = fname; *p2; ++p2)    /* find last part of path */
  1978.     {
  1979.         if (ispathsep(*p2))
  1980.             p1 = p2 + 1;
  1981.     }
  1982.     return p1;
  1983. }
  1984.  
  1985. /*
  1986.  * return TRUE if 'c' is a path separator.
  1987.  */
  1988.     int
  1989. ispathsep(c)
  1990.     int c;
  1991. {
  1992. #ifdef UNIX
  1993.     return (c == PATHSEP);        /* UNIX has ':' inside file names */
  1994. #else
  1995. # ifdef BACKSLASH_IN_FILENAME
  1996.     return (c == ':' || c == PATHSEP || c == '\\');
  1997. # else
  1998.     return (c == ':' || c == PATHSEP);
  1999. # endif
  2000. #endif
  2001. }
  2002.  
  2003. /*
  2004.  * Concatenate filenames fname1 and fname2 into allocated memory.
  2005.  * Only add a '/' when 'sep' is TRUE and it is neccesary.
  2006.  */
  2007.     char_u    *
  2008. concat_fnames(fname1, fname2, sep)
  2009.     char_u    *fname1;
  2010.     char_u    *fname2;
  2011.     int        sep;
  2012. {
  2013.     char_u    *dest;
  2014.  
  2015.     dest = alloc((unsigned)(STRLEN(fname1) + STRLEN(fname2) + 2));
  2016.     if (dest != NULL)
  2017.     {
  2018.         STRCPY(dest, fname1);
  2019.         if (sep && *dest && !ispathsep(*(dest + STRLEN(dest) - 1)))
  2020.             STRCAT(dest, PATHSEPSTR);
  2021.         STRCAT(dest, fname2);
  2022.     }
  2023.     return dest;
  2024. }
  2025.  
  2026. /*
  2027.  * FullName_save - Make an allocated copy of a full file name.
  2028.  * Returns NULL when failed.
  2029.  */
  2030.     char_u     *
  2031. FullName_save(fname)
  2032.     char_u        *fname;
  2033. {
  2034.     char_u        *buf;
  2035.     char_u        *new_fname = NULL;
  2036.  
  2037.     buf = alloc((unsigned)MAXPATHL);
  2038.     if (buf != NULL)
  2039.     {
  2040.         if (FullName(fname, buf, MAXPATHL, FALSE) != FAIL)
  2041.             new_fname = strsave(buf);
  2042.         vim_free(buf);
  2043.     }
  2044.     return new_fname;
  2045. }
  2046.  
  2047. #ifdef CINDENT
  2048.  
  2049. /*
  2050.  * Functions for C-indenting.
  2051.  * Most of this originally comes from Eric Fischer.
  2052.  */
  2053. /*
  2054.  * Below "XXX" means that this function may unlock the current line.
  2055.  */
  2056.  
  2057. static int        isdefault __ARGS((char_u *));
  2058. static char_u    *after_label __ARGS((char_u *l));
  2059. static int        get_indent_nolabel __ARGS((linenr_t lnum));
  2060. static int        skip_label __ARGS((linenr_t, char_u **pp, int ind_maxcomment));
  2061. static int        ispreproc __ARGS((char_u *));
  2062. static int        iscomment __ARGS((char_u *));
  2063. static int        commentorempty __ARGS((char_u *));
  2064. static int        isterminated __ARGS((char_u *));
  2065. static int        isfuncdecl __ARGS((char_u *));
  2066. static char_u    *skip_string __ARGS((char_u *p));
  2067. static int        isif __ARGS((char_u *));
  2068. static int        iselse __ARGS((char_u *));
  2069. static int        isdo __ARGS((char_u *));
  2070. static int        iswhileofdo __ARGS((char_u *, linenr_t, int));
  2071. static FPOS        *find_start_comment __ARGS((int ind_maxcomment));
  2072. static FPOS        *find_start_brace __ARGS((int));
  2073. static FPOS        *find_match_paren __ARGS((int, int));
  2074. static int        find_last_paren __ARGS((char_u *l));
  2075. static int        find_match __ARGS((int lookfor, linenr_t ourscope,
  2076.                         int ind_maxparen, int ind_maxcomment));
  2077.  
  2078. /*
  2079.  * Recognize a label: "label:".
  2080.  * Note: curwin->w_cursor must be where we are looking for the label.
  2081.  */
  2082.     int
  2083. islabel(ind_maxcomment)            /* XXX */
  2084.     int            ind_maxcomment;
  2085. {
  2086.     char_u        *s;
  2087.  
  2088.     s = skipwhite(ml_get_curline());
  2089.  
  2090.     /*
  2091.      * Exclude "default" from labels, since it should be indented
  2092.      * like a switch label.
  2093.      */
  2094.  
  2095.     if (isdefault(s))
  2096.         return FALSE;
  2097.  
  2098.     if (!isidchar(*s))        /* need at least one ID character */
  2099.         return FALSE;
  2100.  
  2101.     while (isidchar(*s))
  2102.         s++;
  2103.  
  2104.     s = skipwhite(s);
  2105.  
  2106.     /* "::" is not a label, it's C++ */
  2107.     if (*s == ':' && s[1] != ':')
  2108.     {
  2109.         /*
  2110.          * Only accept a label if the previous line is terminated or is a case
  2111.          * label.
  2112.          */
  2113.         FPOS    cursor_save;
  2114.         FPOS    *trypos;
  2115.         char_u    *line;
  2116.  
  2117.         cursor_save = curwin->w_cursor;
  2118.         while (curwin->w_cursor.lnum > 1)
  2119.         {
  2120.             --curwin->w_cursor.lnum;
  2121.  
  2122.             /*
  2123.              * If we're in a comment now, skip to the start of the comment.
  2124.              */
  2125.             curwin->w_cursor.col = 0;
  2126.             if ((trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
  2127.                 curwin->w_cursor = *trypos;
  2128.  
  2129.             line = ml_get_curline();
  2130.             if (ispreproc(line))        /* ignore #defines, #if, etc. */
  2131.                 continue;
  2132.             if (commentorempty(line))
  2133.                 continue;
  2134.  
  2135.             curwin->w_cursor = cursor_save;
  2136.             if (isterminated(line) || iscase(line))
  2137.                 return TRUE;
  2138.             return FALSE;
  2139.         }
  2140.         curwin->w_cursor = cursor_save;
  2141.         return TRUE;            /* label at start of file??? */
  2142.     }
  2143.     return FALSE;
  2144. }
  2145.  
  2146. /*
  2147.  * Recognize a switch label: "case .*:" or "default:".
  2148.  */
  2149.      int
  2150. iscase(s)
  2151.     char_u *s;
  2152. {
  2153.     s = skipwhite(s);
  2154.     if (STRNCMP(s, "case", 4) == 0 && !isidchar(s[4]))
  2155.     {
  2156.         for (s += 4; *s; ++s)
  2157.             if (*s == ':')
  2158.             {
  2159.                 if (s[1] == ':')        /* skip over "::" for C++ */
  2160.                     ++s;
  2161.                 else
  2162.                     return TRUE;
  2163.             }
  2164.         return FALSE;
  2165.     }
  2166.  
  2167.     if (isdefault(s))
  2168.         return TRUE;
  2169.     return FALSE;
  2170. }
  2171.  
  2172. /*
  2173.  * Recognize a "default" switch label.
  2174.  */
  2175.     static int
  2176. isdefault(s)
  2177.     char_u    *s;
  2178. {
  2179.     return (STRNCMP(s, "default", 7) == 0 &&
  2180.             *(s = skipwhite(s + 7)) == ':' &&
  2181.             s[1] != ':');
  2182. }
  2183.  
  2184. /*
  2185.  * Return a pointer to the first non-empty non-comment character after a ':'.
  2186.  * Return NULL if not found.
  2187.  *        case 234:    a = b;
  2188.  *                     ^
  2189.  */
  2190.     static char_u *
  2191. after_label(l)
  2192.     char_u    *l;
  2193. {
  2194.     for ( ; *l; ++l)
  2195.         if (*l == ':')
  2196.         {
  2197.             if (l[1] == ':')        /* skip over "::" for C++ */
  2198.                 ++l;
  2199.             else
  2200.                 break;
  2201.         }
  2202.     if (*l == NUL)
  2203.         return NULL;
  2204.     l = skipwhite(l + 1);
  2205.     if (commentorempty(l))
  2206.         return NULL;
  2207.     return l;
  2208. }
  2209.  
  2210. /*
  2211.  * Get indent of line "lnum", skipping a label.
  2212.  * Return 0 if there is nothing after the label.
  2213.  */
  2214.     static int
  2215. get_indent_nolabel(lnum)                /* XXX */
  2216.     linenr_t    lnum;
  2217. {
  2218.     char_u        *l;
  2219.     FPOS        fp;
  2220.     colnr_t        col;
  2221.     char_u        *p;
  2222.  
  2223.     l = ml_get(lnum);
  2224.     p = after_label(l);
  2225.     if (p == NULL)
  2226.         return 0;
  2227.  
  2228.     fp.col = p - l;
  2229.     fp.lnum = lnum;
  2230.     getvcol(curwin, &fp, &col, NULL, NULL);
  2231.     return (int)col;
  2232. }
  2233.  
  2234. /*
  2235.  * Find indent for line "lnum", ignoring any case or jump label.
  2236.  * Also return a pointer to the text (after the label).
  2237.  *   label:        if (asdf && asdfasdf)
  2238.  *              ^
  2239.  */
  2240.     static int
  2241. skip_label(lnum, pp, ind_maxcomment)
  2242.     linenr_t    lnum;
  2243.     char_u        **pp;
  2244.     int            ind_maxcomment;
  2245. {
  2246.     char_u        *l;
  2247.     int            amount;
  2248.     FPOS        cursor_save;
  2249.  
  2250.     cursor_save = curwin->w_cursor;
  2251.     curwin->w_cursor.lnum = lnum;
  2252.     l = ml_get_curline();
  2253.     if (iscase(l) || islabel(ind_maxcomment)) /* XXX */
  2254.     {
  2255.         amount = get_indent_nolabel(lnum);
  2256.         l = after_label(ml_get_curline());
  2257.         if (l == NULL)            /* just in case */
  2258.             l = ml_get_curline();
  2259.     }
  2260.     else
  2261.     {
  2262.         amount = get_indent();
  2263.         l = ml_get_curline();
  2264.     }
  2265.     *pp = l;
  2266.  
  2267.     curwin->w_cursor = cursor_save;
  2268.     return amount;
  2269. }
  2270.  
  2271. /*
  2272.  * Recognize a preprocessor statement: Any line that starts with '#'.
  2273.  */
  2274.     static int
  2275. ispreproc(s)
  2276.     char_u *s;
  2277. {
  2278.     s = skipwhite(s);
  2279.     if (*s == '#')
  2280.         return TRUE;
  2281.     return 0;
  2282. }
  2283.  
  2284. /*
  2285.  * Recognize the start of a C or C++ comment.
  2286.  */
  2287.     static int
  2288. iscomment(p)
  2289.     char_u    *p;
  2290. {
  2291.     return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
  2292. }
  2293.  
  2294. /*
  2295.  * Recognize an empty or comment line.
  2296.  */
  2297.     static int
  2298. commentorempty(s)
  2299.     char_u *s;
  2300. {
  2301.     s = skipwhite(s);
  2302.     if (*s == NUL || iscomment(s))
  2303.         return TRUE;
  2304.     return FALSE;
  2305. }
  2306.  
  2307. /*
  2308.  * Recognize a line that starts with '{' or '}', or ends with ';' or '}'.
  2309.  * Also consider a line terminated if it ends in ','.  This is not 100%
  2310.  * correct, but this mostly means we are in initializations and then it's OK.
  2311.  */
  2312.     static int
  2313. isterminated(s)
  2314.     char_u *s;
  2315. {
  2316.     s = skipwhite(s);
  2317.  
  2318.     if (*s == '{' || *s == '}')
  2319.         return TRUE;
  2320.  
  2321.     while (*s)
  2322.     {
  2323.         if (iscomment(s))        /* at start of comment ignore rest of line */
  2324.             return FALSE;
  2325.         s = skip_string(s);
  2326.         if ((*s == ';' || *s == '{' || *s == ',') && commentorempty(s + 1))
  2327.             return TRUE;
  2328.         s++;
  2329.     }
  2330.     return FALSE;
  2331. }
  2332.  
  2333. /*
  2334.  * Recognize the basic picture of a function declaration -- it needs to
  2335.  * have an open paren somewhere and a close paren at the end of the line and
  2336.  * no semicolons anywhere.
  2337.  */
  2338.     static int
  2339. isfuncdecl(s)
  2340.     char_u *s;
  2341. {
  2342.     while (*s && *s != '(' && *s != ';')
  2343.         if (iscomment(s++))
  2344.             return FALSE;            /* comment before () ??? */
  2345.     if (*s != '(')
  2346.         return FALSE;                /* ';' before any () or no '(' */
  2347.  
  2348.     while (*s && *s != ';')
  2349.     {
  2350.         if (*s == ')' && commentorempty(s + 1))
  2351.             return TRUE;
  2352.         if (iscomment(s++))
  2353.             return FALSE;            /* comment between ( and ) ??? */
  2354.     }
  2355.     return FALSE;
  2356. }
  2357.  
  2358. /*
  2359.  * Skip over a "string" and a 'c' character.
  2360.  */
  2361.     static char_u *
  2362. skip_string(p)
  2363.     char_u    *p;
  2364. {
  2365.     int        i;
  2366.  
  2367.     /*
  2368.      * We loop, because strings may be concatenated: "date""time".
  2369.      */
  2370.     for ( ; ; ++p)
  2371.     {
  2372.         if (p[0] == '\'')                    /* 'c' or '\n' or '\000' */
  2373.         {
  2374.             if (!p[1])                        /* ' at end of line */
  2375.                 break;
  2376.             i = 2;
  2377.             if (p[1] == '\\')                /* '\n' or '\000' */
  2378.             {
  2379.                 ++i;
  2380.                 while (isdigit(p[i - 1]))    /* '\000' */
  2381.                     ++i;
  2382.             }
  2383.             if (p[i] == '\'')                /* check for trailing ' */
  2384.             {
  2385.                 p += i;
  2386.                 continue;
  2387.             }
  2388.         }
  2389.         else if (p[0] == '"')                /* start of string */
  2390.         {
  2391.             for (++p; p[0]; ++p)
  2392.             {
  2393.                 if (p[0] == '\\' && p[1])
  2394.                     ++p;
  2395.                 else if (p[0] == '"')        /* end of string */
  2396.                     break;
  2397.             }
  2398.             continue;
  2399.         }
  2400.         break;                                /* no string found */
  2401.     }
  2402.     if (!*p)
  2403.         --p;                                /* backup from NUL */
  2404.     return p;
  2405. }
  2406.  
  2407.     static int
  2408. isif(p)
  2409.     char_u    *p;
  2410. {
  2411.     return (STRNCMP(p, "if", 2) == 0 && !isidchar(p[2]));
  2412. }
  2413.  
  2414.     static int
  2415. iselse(p)
  2416.     char_u    *p;
  2417. {
  2418.     return (STRNCMP(p, "else", 4) == 0 && !isidchar(p[4]));
  2419. }
  2420.  
  2421.     static int
  2422. isdo(p)
  2423.     char_u    *p;
  2424. {
  2425.     return (STRNCMP(p, "do", 2) == 0 && !isidchar(p[2]));
  2426. }
  2427.  
  2428. /*
  2429.  * Check if this is a "while" that should have a matching "do".
  2430.  * We only accept a "while (condition) ;", with only white space between the
  2431.  * ')' and ';'. The condition may be spread over several lines.
  2432.  */
  2433.     static int
  2434. iswhileofdo(p, lnum, ind_maxparen)            /* XXX */
  2435.     char_u        *p;
  2436.     linenr_t    lnum;
  2437.     int            ind_maxparen;
  2438. {
  2439.     FPOS        cursor_save;
  2440.     FPOS        *trypos;
  2441.     int            retval = FALSE;
  2442.  
  2443.     p = skipwhite(p);
  2444.     if (STRNCMP(p, "while", 5) == 0 && !isidchar(p[5]))
  2445.     {
  2446.         cursor_save = curwin->w_cursor;
  2447.         curwin->w_cursor.lnum = lnum;
  2448.         curwin->w_cursor.col = 0;
  2449.         if ((trypos = findmatchlimit(0, 0, ind_maxparen)) != NULL)
  2450.         {
  2451.             p = ml_get_pos(trypos) + 1;
  2452.             p = skipwhite(p);
  2453.             if (*p == ';')
  2454.                 retval = TRUE;
  2455.         }
  2456.         curwin->w_cursor = cursor_save;
  2457.     }
  2458.     return retval;
  2459. }
  2460.  
  2461. /*
  2462.  * Find the start of a comment, not knowing if we are in a comment right now.
  2463.  * Search starts at w_cursor.lnum and goes backwards.
  2464.  */
  2465.     static FPOS *
  2466. find_start_comment(ind_maxcomment)            /* XXX */
  2467.     int            ind_maxcomment;
  2468. {
  2469.     FPOS        *pos;
  2470.     char_u        *line;
  2471.     char_u        *p;
  2472.  
  2473.     if ((pos = findmatchlimit('*', FM_BACKWARD, ind_maxcomment)) == NULL)
  2474.         return NULL;
  2475.  
  2476.     /*
  2477.      * Check if the comment start we found is inside a string.
  2478.      */
  2479.     line = ml_get(pos->lnum);
  2480.     for (p = line; *p && (unsigned)(p - line) < pos->col; ++p)
  2481.         p = skip_string(p);
  2482.     if ((unsigned)(p - line) > pos->col)
  2483.         return NULL;
  2484.     return pos;
  2485. }
  2486.  
  2487. /*
  2488.  * Find the '{' at the start of the block we are in.
  2489.  * Return NULL of no match found.
  2490.  * Ignore a '{' that is in a comment, makes indenting the next three lines
  2491.  * work. */
  2492. /* foo()    */
  2493. /* {        */
  2494. /* }        */
  2495.  
  2496.     static FPOS *
  2497. find_start_brace(ind_maxcomment)            /* XXX */
  2498.     int            ind_maxcomment;
  2499. {
  2500.     FPOS        cursor_save;
  2501.     FPOS        *trypos;
  2502.     FPOS        *pos;
  2503.     static FPOS    pos_copy;
  2504.  
  2505.     cursor_save = curwin->w_cursor;
  2506.     while ((trypos = findmatchlimit('{', FM_BLOCKSTOP, 0)) != NULL)
  2507.     {
  2508.         pos_copy = *trypos;        /* copy FPOS, next findmatch will change it */
  2509.         trypos = &pos_copy;
  2510.         curwin->w_cursor = *trypos;
  2511.         pos = NULL;
  2512.         if (!iscomment(skipwhite(ml_get(trypos->lnum))) &&
  2513.                  (pos = find_start_comment(ind_maxcomment)) == NULL) /* XXX */
  2514.             break;
  2515.         if (pos != NULL)
  2516.             curwin->w_cursor.lnum = pos->lnum;
  2517.     }
  2518.     curwin->w_cursor = cursor_save;
  2519.     return trypos;
  2520. }
  2521.  
  2522. /*
  2523.  * Find the matching '(', failing if it is in a comment.
  2524.  * Return NULL of no match found.
  2525.  */
  2526.     static FPOS *
  2527. find_match_paren(ind_maxparen, ind_maxcomment)        /* XXX */
  2528.     int            ind_maxparen;
  2529.     int            ind_maxcomment;
  2530. {
  2531.     FPOS        cursor_save;
  2532.     FPOS        *trypos;
  2533.     static FPOS    pos_copy;
  2534.  
  2535.     cursor_save = curwin->w_cursor;
  2536.     if ((trypos = findmatchlimit('(', 0, ind_maxparen)) != NULL)
  2537.     {
  2538.         if (iscomment(skipwhite(ml_get(trypos->lnum))))
  2539.             trypos = NULL;
  2540.         else
  2541.         {
  2542.             pos_copy = *trypos;        /* copy trypos, findmatch will change it */
  2543.             trypos = &pos_copy;
  2544.             curwin->w_cursor = *trypos;
  2545.             if (find_start_comment(ind_maxcomment) != NULL)    /* XXX */
  2546.                 trypos = NULL;
  2547.         }
  2548.     }
  2549.     curwin->w_cursor = cursor_save;
  2550.     return trypos;
  2551. }
  2552.  
  2553. /*
  2554.  * Set w_cursor.col to the column number of the last ')' in line "l".
  2555.  */
  2556.     static int
  2557. find_last_paren(l)
  2558.     char_u *l;
  2559. {
  2560.     int        i;
  2561.     int        retval = FALSE;
  2562.  
  2563.     curwin->w_cursor.col = 0;                /* default is start of line */
  2564.  
  2565.     for (i = 0; l[i]; i++)
  2566.     {
  2567.         i = skip_string(l + i) - l;            /* ignore parens in quotes */
  2568.         if (l[i] == ')')
  2569.         {
  2570.             curwin->w_cursor.col = i;
  2571.             retval = TRUE;
  2572.         }
  2573.     }
  2574.     return retval;
  2575. }
  2576.  
  2577.     int
  2578. get_c_indent()
  2579. {
  2580.     /*
  2581.      * spaces from a block's opening brace the prevailing indent for that
  2582.      * block should be
  2583.      */
  2584.     int ind_level = curbuf->b_p_sw;
  2585.  
  2586.     /*
  2587.      * spaces from the edge of the line an open brace that's at the end of a
  2588.      * line is imagined to be.
  2589.      */
  2590.     int ind_open_imag = 0;
  2591.  
  2592.     /*
  2593.      * spaces from the prevailing indent for a line that is not precededof by
  2594.      * an opening brace.
  2595.      */
  2596.     int ind_no_brace = 0;
  2597.  
  2598.     /*
  2599.      * column where the first { of a function should be located
  2600.      */
  2601.     int ind_first_open = 0;
  2602.  
  2603.     /*
  2604.      * spaces from the prevailing indent a leftmost open brace should be
  2605.      * located
  2606.      */
  2607.     int ind_open_extra = 0;
  2608.  
  2609.     /*
  2610.      * spaces from the matching open brace (real location for one at the left
  2611.      * edge; imaginary location from one that ends a line) the matching close
  2612.      * brace should be located
  2613.      */
  2614.     int ind_close_extra = 0;
  2615.  
  2616.     /*
  2617.      * spaces from the edge of the line an open brace sitting in the leftmost
  2618.      * column is imagined to be
  2619.      */
  2620.     int ind_open_left_imag = 0;
  2621.  
  2622.     /*
  2623.      * spaces from the switch() indent a "case xx" label should be located
  2624.      */
  2625.     int ind_case = curbuf->b_p_sw;
  2626.  
  2627.     /*
  2628.      * spaces from the "case xx:" code after a switch() should be located
  2629.      */
  2630.     int ind_case_code = curbuf->b_p_sw;
  2631.  
  2632.     /*
  2633.      * amount K&R-style parameters should be indented
  2634.      */
  2635.     int ind_param = curbuf->b_p_sw;
  2636.  
  2637.     /*
  2638.      * amount a function type spec should be indented
  2639.      */
  2640.     int ind_func_type = curbuf->b_p_sw;
  2641.  
  2642.     /*
  2643.      * additional spaces beyond the prevailing indent a continuation line
  2644.      * should be located
  2645.      */
  2646.     int ind_continuation = curbuf->b_p_sw;
  2647.  
  2648.     /*
  2649.      * spaces from the indent of the line with an unclosed parentheses
  2650.      */
  2651.     int ind_unclosed = curbuf->b_p_sw * 2;
  2652.  
  2653.     /*
  2654.      * spaces from the comment opener when there is nothing after it.
  2655.      */
  2656.     int ind_in_comment = 3;
  2657.  
  2658.     /*
  2659.      * max lines to search for an open paren
  2660.      */
  2661.     int ind_maxparen = 20;
  2662.  
  2663.     /*
  2664.      * max lines to search for an open comment
  2665.      */
  2666.     int ind_maxcomment = 30;
  2667.  
  2668.     FPOS        cur_curpos;
  2669.     int            amount;
  2670.     int            scope_amount;
  2671.     int            cur_amount;
  2672.     colnr_t        col;
  2673.     char_u        *theline;
  2674.     char_u        *linecopy;
  2675.     FPOS        *trypos;
  2676.     FPOS        our_paren_pos;
  2677.     char_u        *start;
  2678.     int            start_brace;
  2679. #define BRACE_IN_COL0    1            /* '{' is in comumn 0 */
  2680. #define BRACE_AT_START    2            /* '{' is at start of line */
  2681. #define BRACE_AT_END    3            /* '{' is at end of line */
  2682.     linenr_t    ourscope;
  2683.     char_u        *l;
  2684.     char_u        *look;
  2685.     int            lookfor;
  2686. #define LOOKFOR_IF        1
  2687. #define LOOKFOR_DO        2
  2688. #define LOOKFOR_CASE    3
  2689. #define LOOKFOR_ANY        4
  2690. #define LOOKFOR_TERM    5
  2691. #define LOOKFOR_UNTERM    6
  2692.     int            whilelevel;
  2693.     linenr_t    lnum;
  2694.     char_u        *options;
  2695.     int            fraction = 0;        /* init for GCC */
  2696.     int            divider;
  2697.     int            n;
  2698.  
  2699.     for (options = curbuf->b_p_cino; *options; )
  2700.     {
  2701.         l = options++;
  2702.         if (*options == '-')
  2703.             ++options;
  2704.         n = getdigits(&options);
  2705.         divider = 0;
  2706.         if (*options == '.')        /* ".5s" means a fraction */
  2707.         {
  2708.             fraction = atol((char *)++options);
  2709.             while (isdigit(*options))
  2710.             {
  2711.                 ++options;
  2712.                 if (divider)
  2713.                     divider *= 10;
  2714.                 else
  2715.                     divider = 10;
  2716.             }
  2717.         }
  2718.         if (*options == 's')        /* "2s" means two times 'shiftwidth' */
  2719.         {
  2720.             if (n == 0 && fraction == 0)
  2721.                 n = curbuf->b_p_sw;        /* just "s" is one 'shiftwidth' */
  2722.             else
  2723.             {
  2724.                 n *= curbuf->b_p_sw;
  2725.                 if (divider)
  2726.                     n += (curbuf->b_p_sw * fraction + divider / 2) / divider;
  2727.             }
  2728.             ++options;
  2729.         }
  2730.         if (l[1] == '-')
  2731.             n = -n;
  2732.         switch (*l)
  2733.         {
  2734.             case '>': ind_level = n; break;
  2735.             case 'e': ind_open_imag = n; break;
  2736.             case 'n': ind_no_brace = n; break;
  2737.             case 'f': ind_first_open = n; break;
  2738.             case '{': ind_open_extra = n; break;
  2739.             case '}': ind_close_extra = n; break;
  2740.             case '^': ind_open_left_imag = n; break;
  2741.             case ':': ind_case = n; break;
  2742.             case '=': ind_case_code = n; break;
  2743.             case 'p': ind_param = n; break;
  2744.             case 't': ind_func_type = n; break;
  2745.             case 'c': ind_in_comment = n; break;
  2746.             case '+': ind_continuation = n; break;
  2747.             case '(': ind_unclosed = n; break;
  2748.             case ')': ind_maxparen = n; break;
  2749.             case '*': ind_maxcomment = n; break;
  2750.         }
  2751.     }
  2752.  
  2753.     /* remember where the cursor was when we started */
  2754.  
  2755.     cur_curpos = curwin->w_cursor;
  2756.  
  2757.     /* get the current contents of the line.
  2758.      * This is required, because onle the most recent line obtained with
  2759.      * ml_get is valid! */
  2760.  
  2761.     linecopy = strsave(ml_get(cur_curpos.lnum));
  2762.     if (linecopy == NULL)
  2763.         return 0;
  2764.  
  2765.     /*
  2766.      * In insert mode and the cursor is on a ')' trunctate the line at the
  2767.      * cursor position.  We don't want to line up with the matching '(' when
  2768.      * inserting new stuff.
  2769.      */
  2770.     if ((State & INSERT) && linecopy[curwin->w_cursor.col] == ')')
  2771.         linecopy[curwin->w_cursor.col] = NUL;
  2772.  
  2773.     theline = skipwhite(linecopy);
  2774.  
  2775.     /* move the cursor to the start of the line */
  2776.  
  2777.     curwin->w_cursor.col = 0;
  2778.  
  2779.     /*
  2780.      * #defines and so on always go at the left when included in 'cinkeys'.
  2781.      */
  2782.     if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
  2783.     {
  2784.         amount = 0;
  2785.     }
  2786.  
  2787.     /* 
  2788.      * Is it a non-case label?  Then that goes at the left margin too.
  2789.        */
  2790.     else if (islabel(ind_maxcomment))        /* XXX */
  2791.     {
  2792.         amount = 0;
  2793.     }
  2794.  
  2795.     /* 
  2796.      * If we're inside a comment and not looking at the start of the
  2797.      * comment...
  2798.      */
  2799.     else if (!iscomment(theline) &&
  2800.               (trypos = find_start_comment(ind_maxcomment)) != NULL) /* XXX */
  2801.     {
  2802.  
  2803.         /* find how indented the line beginning the comment is */
  2804.         getvcol(curwin, trypos, &col, NULL, NULL);
  2805.         amount = col;
  2806.  
  2807.         /* if our line starts with an asterisk, line up with the
  2808.          * asterisk in the comment opener; otherwise, line up
  2809.          * with the first character of the comment text.
  2810.          */
  2811.         if (theline[0] == '*')
  2812.         {
  2813.             amount += 1;
  2814.         }
  2815.         else
  2816.         {
  2817.             /*
  2818.              * If we are more than one line away from the comment opener, take
  2819.              * the indent of the previous non-empty line.
  2820.              * If we are just below the comment opener and there are any
  2821.              * white characters after it line up with the text after it.
  2822.              * up with them; otherwise, just use a single space.
  2823.              */
  2824.             amount = -1;
  2825.             for (lnum = cur_curpos.lnum - 1; lnum > trypos->lnum; --lnum)
  2826.             {
  2827.                 if (linewhite(lnum))                /* skip blank lines */
  2828.                     continue;
  2829.                 amount = get_indent_lnum(lnum);        /* XXX */
  2830.                 break;
  2831.             }
  2832.             if (amount == -1)                        /* use the comment opener */
  2833.             {
  2834.                 start = ml_get(trypos->lnum);
  2835.                 look = start + trypos->col + 2;      /* skip / and * */
  2836.                 if (*look)                            /* if something after it */
  2837.                     trypos->col = skipwhite(look) - start;
  2838.                 getvcol(curwin, trypos, &col, NULL, NULL);
  2839.                 amount = col;
  2840.                 if (!*look)
  2841.                     amount += ind_in_comment;
  2842.             }
  2843.         }
  2844.     }
  2845.  
  2846.     /*
  2847.      * Are we inside parentheses?
  2848.      */                                                /* XXX */
  2849.     else if ((trypos = find_match_paren(ind_maxparen, ind_maxcomment)) != NULL)
  2850.     {
  2851.         /*
  2852.          * If the matching paren is more than one line away, use the indent of
  2853.          * a previous non-empty line that matches the same paren.
  2854.          */
  2855.         amount = -1;
  2856.         our_paren_pos = *trypos;
  2857.         if (theline[0] != ')')
  2858.         {
  2859.             for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
  2860.             {
  2861.                 l = skipwhite(ml_get(lnum));
  2862.                 if (commentorempty(l))        /* skip comment lines */
  2863.                     continue;
  2864.                 if (ispreproc(l))            /* ignore #defines, #if, etc. */
  2865.                     continue;
  2866.                 curwin->w_cursor.lnum = lnum;
  2867.                 /* XXX */
  2868.                 if ((trypos = find_match_paren(ind_maxparen,
  2869.                                                    ind_maxcomment)) != NULL &&
  2870.                                          trypos->lnum == our_paren_pos.lnum &&
  2871.                                              trypos->col == our_paren_pos.col)
  2872.                 {
  2873.                     amount = get_indent_lnum(lnum);        /* XXX */
  2874.                     break;
  2875.                 }
  2876.             }
  2877.         }
  2878.  
  2879.         /*
  2880.          * Line up with line where the matching paren is.
  2881.          * If the line starts with a '(' or the indent for unclosed
  2882.          * parentheses is zero, line up with the unclosed parentheses.
  2883.          */
  2884.         if (amount == -1)
  2885.         {
  2886.             amount = skip_label(our_paren_pos.lnum, &look, ind_maxcomment);
  2887.             if (theline[0] == ')' || ind_unclosed == 0 ||
  2888.                                                       *skipwhite(look) == '(')
  2889.             {
  2890.  
  2891.                 /* 
  2892.                  * If we're looking at a close paren, line up right there;
  2893.                  * otherwise, line up with the next non-white character.
  2894.                  */
  2895.                 if (theline[0] != ')')
  2896.                 {
  2897.                     col = our_paren_pos.col + 1;
  2898.                     look = ml_get(our_paren_pos.lnum);
  2899.                     while (vim_iswhite(look[col]))
  2900.                         col++;
  2901.                     if (look[col] != NUL)        /* In case of trailing space */
  2902.                         our_paren_pos.col = col;
  2903.                     else
  2904.                         our_paren_pos.col++;
  2905.                 }
  2906.  
  2907.                 /*
  2908.                  * Find how indented the paren is, or the character after it if
  2909.                  * we did the above "if".
  2910.                  */
  2911.                 getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
  2912.                 amount = col;
  2913.             }
  2914.             else
  2915.                 amount += ind_unclosed;
  2916.         }
  2917.     }
  2918.  
  2919.     /*
  2920.      * Are we at least inside braces, then?
  2921.      */
  2922.     else if ((trypos = find_start_brace(ind_maxcomment)) != NULL) /* XXX */
  2923.     {
  2924.         ourscope = trypos->lnum;
  2925.         start = ml_get(ourscope);
  2926.  
  2927.         /* 
  2928.          * Now figure out how indented the line is in general.
  2929.          * If the brace was at the start of the line, we use that;
  2930.          * otherwise, check out the indentation of the line as
  2931.          * a whole and then add the "imaginary indent" to that.
  2932.          */
  2933.         look = skipwhite(start);
  2934.         if (*look == '{')
  2935.         {
  2936.             getvcol(curwin, trypos, &col, NULL, NULL);
  2937.             amount = col;
  2938.             if (*start == '{')
  2939.                 start_brace = BRACE_IN_COL0;
  2940.             else
  2941.                 start_brace = BRACE_AT_START;
  2942.         }
  2943.         else
  2944.         {
  2945.             /* 
  2946.              * that opening brace might have been on a continuation
  2947.              * line.  if so, find the start of the line.
  2948.              */
  2949.             curwin->w_cursor.lnum = ourscope;
  2950.  
  2951.             /* 
  2952.              * position the cursor over the rightmost paren, so that
  2953.              * matching it will take us back to the start of the line.
  2954.              */
  2955.             lnum = ourscope;
  2956.             if (find_last_paren(start) &&
  2957.                     (trypos = find_match_paren(ind_maxparen,
  2958.                                                      ind_maxcomment)) != NULL)
  2959.                 lnum = trypos->lnum;
  2960.  
  2961.             /*
  2962.              * It could have been something like
  2963.              *     case 1: if (asdf &&
  2964.              *                     ldfd) {
  2965.              *                 }
  2966.              */
  2967.             amount = skip_label(lnum, &l, ind_maxcomment);
  2968.  
  2969.             start_brace = BRACE_AT_END;
  2970.         }
  2971.  
  2972.         /* 
  2973.          * if we're looking at a closing brace, that's where
  2974.          * we want to be.  otherwise, add the amount of room
  2975.          * that an indent is supposed to be.
  2976.          */
  2977.         if (theline[0] == '}')
  2978.         {
  2979.             /* 
  2980.              * they may want closing braces to line up with something
  2981.              * other than the open brace.  indulge them, if so. 
  2982.              */
  2983.             amount += ind_close_extra;
  2984.         }
  2985.         else
  2986.         {
  2987.             /* 
  2988.              * If we're looking at an "else", try to find an "if"
  2989.              * to match it with.
  2990.              * If we're looking at a "while", try to find a "do"
  2991.              * to match it with.
  2992.              */
  2993.             lookfor = 0;
  2994.             if (iselse(theline))
  2995.                 lookfor = LOOKFOR_IF;
  2996.             else if (iswhileofdo(theline, cur_curpos.lnum, ind_maxparen))
  2997.                                                                     /* XXX */
  2998.                 lookfor = LOOKFOR_DO;
  2999.             if (lookfor)
  3000.             {
  3001.                 curwin->w_cursor.lnum = cur_curpos.lnum;
  3002.                 if (find_match(lookfor, ourscope, ind_maxparen,
  3003.                                                         ind_maxcomment) == OK)
  3004.                 {
  3005.                     amount = get_indent();        /* XXX */
  3006.                     goto theend;
  3007.                 }
  3008.             }
  3009.  
  3010.             /* 
  3011.              * We get here if we are not on an "while-of-do" or "else" (or
  3012.              * failed to find a matching "if").
  3013.              * Search backwards for something to line up with.
  3014.              * First set amount for when we don't find anything.
  3015.              */
  3016.  
  3017.             /* 
  3018.              * if the '{' is  _really_ at the left margin, use the imaginary
  3019.              * location of a left-margin brace.  Otherwise, correct the
  3020.              * location for ind_open_extra.
  3021.              */
  3022.  
  3023.             if (start_brace == BRACE_IN_COL0)        /* '{' is in column 0 */
  3024.             {
  3025.                 amount = ind_open_left_imag;
  3026.             }
  3027.             else 
  3028.             {
  3029.                 if (start_brace == BRACE_AT_END)    /* '{' is at end of line */
  3030.                     amount += ind_open_imag;
  3031.                 else
  3032.                 {
  3033.                     amount -= ind_open_extra;
  3034.                     if (amount < 0)
  3035.                         amount = 0;
  3036.                 }
  3037.             }
  3038.  
  3039.             if (iscase(theline))        /* it's a switch() label */
  3040.             {
  3041.                 lookfor = LOOKFOR_CASE;    /* find a previous switch() label */
  3042.                 amount += ind_case;
  3043.             }
  3044.             else
  3045.             {
  3046.                 lookfor = LOOKFOR_ANY;
  3047.                 amount += ind_level;    /* ind_level from start of block */
  3048.             }
  3049.             scope_amount = amount;
  3050.             whilelevel = 0;
  3051.  
  3052.             /*
  3053.              * Search backwards.  If we find something we recognize, line up
  3054.              * with that.
  3055.              *
  3056.              * if we're looking at an open brace, indent
  3057.              * the usual amount relative to the conditional
  3058.              * that opens the block.
  3059.              */
  3060.             curwin->w_cursor = cur_curpos;
  3061.             for (;;)
  3062.             {
  3063.                 curwin->w_cursor.lnum--;
  3064.                 curwin->w_cursor.col = 0;
  3065.  
  3066.                 /*
  3067.                  * If we went all the way back to the start of our scope, line
  3068.                  * up with it.
  3069.                  */
  3070.                 if (curwin->w_cursor.lnum <= ourscope)
  3071.                 {
  3072.                     if (lookfor == LOOKFOR_UNTERM)
  3073.                         amount += ind_continuation;
  3074.                     else if (lookfor != LOOKFOR_TERM)
  3075.                         amount = scope_amount;
  3076.                     break;
  3077.                 }
  3078.  
  3079.                 /*
  3080.                  * If we're in a comment now, skip to the start of the comment.
  3081.                  */                                            /* XXX */
  3082.                 if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  3083.                 {
  3084.                     curwin->w_cursor.lnum = trypos->lnum + 1;
  3085.                     continue;
  3086.                 }
  3087.  
  3088.                 l = ml_get_curline();
  3089.  
  3090.                 /*
  3091.                  * If this is a switch() label, may line up relative to that.
  3092.                  */
  3093.                 if (iscase(l))
  3094.                 {
  3095.                     /*
  3096.                      *  case xx:
  3097.                      *         c = 99 +        <- this indent plus continuation
  3098.                      *->           here;
  3099.                      */
  3100.                     if (lookfor == LOOKFOR_UNTERM)
  3101.                     {
  3102.                         amount += ind_continuation;
  3103.                         break;
  3104.                     }
  3105.  
  3106.                     /*
  3107.                      *  case xx:        <- line up with this case
  3108.                      *      x = 333;
  3109.                      *  case yy:
  3110.                      */
  3111.                     if (lookfor == LOOKFOR_CASE)
  3112.                     {
  3113.                         /*
  3114.                          * Check that this case label is not for another
  3115.                          * switch()
  3116.                          */                                    /* XXX */
  3117.                         if ((trypos = find_start_brace(ind_maxcomment)) ==
  3118.                                              NULL || trypos->lnum == ourscope)
  3119.                         {
  3120.                             amount = get_indent();        /* XXX */
  3121.                             break;
  3122.                         }
  3123.                         continue;
  3124.                     }
  3125.  
  3126.                     n = get_indent_nolabel(curwin->w_cursor.lnum);  /* XXX */
  3127.  
  3128.                     /*
  3129.                      *   case xx: if (cond)            <- line up with this if
  3130.                      *                y = y + 1;
  3131.                      * ->         s = 99;
  3132.                      *
  3133.                      *   case xx:
  3134.                      *       if (cond)            <- line up with this line
  3135.                      *           y = y + 1;
  3136.                      * ->    s = 99;
  3137.                      */
  3138.                     if (lookfor == LOOKFOR_TERM)
  3139.                     {
  3140.                         if (n)
  3141.                             amount = n;
  3142.                         break;
  3143.                     }
  3144.  
  3145.                     /*
  3146.                      *   case xx: x = x + 1;        <- line up with this x
  3147.                      * ->         y = y + 1;
  3148.                      *
  3149.                      *   case xx: if (cond)            <- line up with this if
  3150.                      * ->              y = y + 1;
  3151.                      */
  3152.                     if (n)
  3153.                     {
  3154.                         amount = n;
  3155.                         l = after_label(ml_get_curline());
  3156.                         if (l != NULL && is_cinword(l))
  3157.                             amount += ind_level + ind_no_brace;
  3158.                         break;
  3159.                     }
  3160.  
  3161.                     /*
  3162.                      *   Try to get the indent of a statement before the
  3163.                      *   switch label.  If nothing is found, line up relative
  3164.                      *   to the switch label.
  3165.                      *       break;                <- may line up with this line
  3166.                      *   case xx:
  3167.                      * ->   y = 1;
  3168.                      */
  3169.                     scope_amount = get_indent() + ind_case_code;    /* XXX */
  3170.                     lookfor = LOOKFOR_ANY;
  3171.                     continue;
  3172.                 }
  3173.  
  3174.                 /*
  3175.                  * Looking for a switch() label, ignore other lines.
  3176.                  */
  3177.                 if (lookfor == LOOKFOR_CASE)
  3178.                     continue;
  3179.  
  3180.                 /*
  3181.                  * Ignore jump labels with nothing after them.
  3182.                  */
  3183.                 if (islabel(ind_maxcomment))
  3184.                 {
  3185.                     l = after_label(ml_get_curline());
  3186.                     if (l == NULL || commentorempty(l))
  3187.                         continue;
  3188.                 }
  3189.  
  3190.                 /*
  3191.                  * Ignore #defines, #if, etc.
  3192.                  * Ignore comment and empty lines.
  3193.                  * (need to get the line again, islabel() may have unlocked it)
  3194.                  */
  3195.                 l = ml_get_curline();
  3196.                 if (ispreproc(l) || commentorempty(l))
  3197.                     continue;
  3198.  
  3199.                 /*
  3200.                  * What happens next depends on the line being terminated.
  3201.                  */
  3202.                 if (!isterminated(l))
  3203.                 {
  3204.                     /* 
  3205.                      * if we're in the middle of a paren thing,
  3206.                      * go back to the line that starts it so
  3207.                      * we can get the right prevailing indent
  3208.                      *     if ( foo &&
  3209.                      *                 bar )
  3210.                      */
  3211.                     /* 
  3212.                      * position the cursor over the rightmost paren, so that
  3213.                      * matching it will take us back to the start of the line.
  3214.                      */
  3215.                     (void)find_last_paren(l);
  3216.                     if ((trypos = find_match_paren(ind_maxparen,
  3217.                                                      ind_maxcomment)) != NULL)
  3218.                     {
  3219.                         /*
  3220.                          * Check if we are on a case label now.  This is
  3221.                          * handled above.
  3222.                          *     case xx:  if ( asdf &&
  3223.                          *                      asdf)
  3224.                          */
  3225.                         curwin->w_cursor.lnum = trypos->lnum;
  3226.                         l = ml_get_curline();
  3227.                         if (iscase(l))
  3228.                         {
  3229.                             ++curwin->w_cursor.lnum;
  3230.                             continue;
  3231.                         }
  3232.                     }
  3233.  
  3234.                     /*
  3235.                      * Get indent and pointer to text for current line,
  3236.                      * ignoring any jump label.        XXX
  3237.                      */
  3238.                     cur_amount = skip_label(curwin->w_cursor.lnum,
  3239.                                                           &l, ind_maxcomment);
  3240.  
  3241.                     /*
  3242.                      * If this is just above the line we are indenting, and it
  3243.                      * starts with a '{', line it up with this line.
  3244.                      *             while (not)
  3245.                      * ->        {
  3246.                      *             }
  3247.                      */
  3248.                     if (lookfor != LOOKFOR_TERM && theline[0] == '{')
  3249.                     {
  3250.                         amount = cur_amount + ind_open_extra;
  3251.                         break;
  3252.                     }
  3253.  
  3254.                     /*
  3255.                      * Check if we are after an "if", "while", etc.
  3256.                      */
  3257.                     if (is_cinword(l))
  3258.                     {
  3259.                         /*
  3260.                          * Found an unterminated line after an if (), line up
  3261.                          * with the last one.
  3262.                          *     if (cond)
  3263.                          *            100 +
  3264.                          * ->            here;
  3265.                          */
  3266.                         if (lookfor == LOOKFOR_UNTERM)
  3267.                         {
  3268.                             amount += ind_continuation;
  3269.                             break;
  3270.                         }
  3271.  
  3272.                         /*
  3273.                          * If this is just above the line we are indenting, we
  3274.                          * are finished.
  3275.                          *             while (not)
  3276.                          * ->            here;
  3277.                          * Otherwise this indent can be used when the line
  3278.                          * before this is terminated.
  3279.                          *         yyy;
  3280.                          *         if (stat)
  3281.                          *             while (not)
  3282.                          *                 xxx;
  3283.                          * ->    here;
  3284.                          */
  3285.                         amount = cur_amount;
  3286.                         if (lookfor != LOOKFOR_TERM)
  3287.                         {
  3288.                             amount += ind_level + ind_no_brace;
  3289.                             break;
  3290.                         }
  3291.  
  3292.                         /*
  3293.                          * Special trick: when expecting the while () after a
  3294.                          * do, line up with the while()
  3295.                          *     do
  3296.                          *          x = 1;
  3297.                          * ->  here
  3298.                          */
  3299.                         l = skipwhite(ml_get_curline());
  3300.                         if (isdo(l))
  3301.                         {
  3302.                             if (whilelevel == 0)
  3303.                                 break;
  3304.                             --whilelevel;
  3305.                         }
  3306.  
  3307.                         /*
  3308.                          * When searching for a terminated line, don't use the
  3309.                          * one between the "if" and the "else".
  3310.                          */
  3311.                         if (iselse(l))
  3312.                         {
  3313.                             if (find_match(LOOKFOR_IF, ourscope,
  3314.                                         ind_maxparen, ind_maxcomment) == FAIL)
  3315.                                 break;
  3316.                         }
  3317.                     }
  3318.  
  3319.                     /* 
  3320.                      * If we're below an unterminated line that is not an
  3321.                      * "if" or something, we may line up with this line or
  3322.                      * add someting for a continuation line, depending on
  3323.                      * the line before this one.
  3324.                      */
  3325.                     else
  3326.                     {
  3327.                         /*
  3328.                          * Found two unterminated lines on a row, line up with
  3329.                          * the last one.
  3330.                          *     c = 99 +
  3331.                          *            100 +
  3332.                          * ->        here;
  3333.                          */
  3334.                         if (lookfor == LOOKFOR_UNTERM)
  3335.                             break;
  3336.  
  3337.                         /*
  3338.                          * Found first unterminated line on a row, may line up
  3339.                          * with this line, remember its indent
  3340.                          *            100 +
  3341.                          * ->        here;
  3342.                          */
  3343.                         amount = cur_amount;
  3344.                         if (lookfor != LOOKFOR_TERM)
  3345.                             lookfor = LOOKFOR_UNTERM;
  3346.                     }
  3347.                 }
  3348.  
  3349.                 /*
  3350.                  * Check if we are after a while (cond);
  3351.                  * If so: Ignore the matching "do".
  3352.                  */
  3353.                                                         /* XXX */
  3354.                 else if (iswhileofdo(l, curwin->w_cursor.lnum, ind_maxparen))
  3355.                 {
  3356.                     /*
  3357.                      * Found an unterminated line after a while ();, line up
  3358.                      * with the last one.
  3359.                      *        while (cond);
  3360.                      *        100 +                <- line up with this one
  3361.                      * ->            here;
  3362.                      */
  3363.                     if (lookfor == LOOKFOR_UNTERM)
  3364.                     {
  3365.                         amount += ind_continuation;
  3366.                         break;
  3367.                     }
  3368.  
  3369.                     if (whilelevel == 0)
  3370.                     {
  3371.                         lookfor = LOOKFOR_TERM;
  3372.                         amount = get_indent();        /* XXX */
  3373.                         if (theline[0] == '{')
  3374.                             amount += ind_open_extra;
  3375.                     }
  3376.                     ++whilelevel;
  3377.                 }
  3378.  
  3379.                 /*
  3380.                  * We are after a "normal" statement.
  3381.                  * If we had another statement we can stop now and use the
  3382.                  * indent of that other statement.
  3383.                  * Otherwise the indent of the current statement may be used,
  3384.                  * search backwards for the next "normal" statement.
  3385.                  */
  3386.                 else
  3387.                 {
  3388.                     /*
  3389.                      * Found a terminated line above an unterminated line. Add
  3390.                      * the amount for a continuation line.
  3391.                      *   x = 1;
  3392.                      *   y = foo +
  3393.                      * ->        here;
  3394.                      */
  3395.                     if (lookfor == LOOKFOR_UNTERM)
  3396.                     {
  3397.                         amount += ind_continuation;
  3398.                         break;
  3399.                     }
  3400.  
  3401.                     /*
  3402.                      * Found a terminated line above a terminated line or "if"
  3403.                      * etc. line. Use the amount of the line below us.
  3404.                      *   x = 1;                            x = 1;
  3405.                      *   if (asdf)                    y = 2;
  3406.                      *         while (asdf)         ->here;
  3407.                      *             here;
  3408.                      * ->foo;
  3409.                      */
  3410.                     if (lookfor == LOOKFOR_TERM)
  3411.                     {
  3412.                         if (whilelevel == 0)
  3413.                             break;
  3414.                     }
  3415.  
  3416.                     /*
  3417.                      * First line above the one we're indenting is terminated.
  3418.                      * To know what needs to be done look further backward for
  3419.                      * a terminated line.
  3420.                      */
  3421.                     else
  3422.                     {
  3423.                         /* 
  3424.                          * position the cursor over the rightmost paren, so
  3425.                          * that matching it will take us back to the start of
  3426.                          * the line.  Helps for:
  3427.                          *     func(asdr,
  3428.                          *            asdfasdf);
  3429.                          *     here;
  3430.                          */
  3431.                         l = ml_get_curline();
  3432.                         if (find_last_paren(l) &&
  3433.                                 (trypos = find_match_paren(ind_maxparen,
  3434.                                                      ind_maxcomment)) != NULL)
  3435.                         {
  3436.                             /*
  3437.                              * Check if we are on a case label now.  This is
  3438.                              * handled above.
  3439.                              *     case xx:  if ( asdf &&
  3440.                              *                      asdf)
  3441.                              */
  3442.                             curwin->w_cursor.lnum = trypos->lnum;
  3443.                             l = ml_get_curline();
  3444.                             if (iscase(l))
  3445.                             {
  3446.                                 ++curwin->w_cursor.lnum;
  3447.                                 continue;
  3448.                             }
  3449.                         }
  3450.  
  3451.                         /*
  3452.                          * Get indent and pointer to text for current line,
  3453.                          * ignoring any jump label.
  3454.                          */
  3455.                         amount = skip_label(curwin->w_cursor.lnum,
  3456.                                                           &l, ind_maxcomment);
  3457.  
  3458.                         if (theline[0] == '{')
  3459.                             amount += ind_open_extra;
  3460.                         lookfor = LOOKFOR_TERM;
  3461.  
  3462.                         /*
  3463.                          * If we're at the end of a block, skip to the start of
  3464.                          * that block.
  3465.                          */
  3466.                         if (*skipwhite(l) == '}' &&
  3467.                                    (trypos = find_start_brace(ind_maxcomment))
  3468.                                                             != NULL) /* XXX */
  3469.                             curwin->w_cursor.lnum = trypos->lnum;
  3470.                     }
  3471.                 }
  3472.             }
  3473.         }
  3474.     }
  3475.  
  3476.     /* 
  3477.      * ok -- we're not inside any sort of structure at all!
  3478.      *
  3479.      * this means we're at the top level, and everything should
  3480.      * basically just match where the previous line is, except
  3481.      * for the lines immediately following a function declaration,
  3482.      * which are K&R-style parameters and need to be indented.
  3483.      */
  3484.     else
  3485.     {
  3486.         /* 
  3487.          * if our line starts with an open brace, forget about any 
  3488.          * prevailing indent and make sure it looks like the start 
  3489.          * of a function
  3490.          */
  3491.  
  3492.         if (theline[0] == '{')
  3493.         {
  3494.             amount = ind_first_open;
  3495.         }
  3496.  
  3497.         /* 
  3498.          * If the NEXT line is a function declaration, the current
  3499.          * line needs to be indented as a function type spec.
  3500.          * Don't do this if the current line looks like a comment.
  3501.          */
  3502.         else if (cur_curpos.lnum < curbuf->b_ml.ml_line_count &&
  3503.                                                    !commentorempty(theline) &&
  3504.                                       isfuncdecl(ml_get(cur_curpos.lnum + 1)))
  3505.         {
  3506.             amount = ind_func_type;
  3507.         }
  3508.         else
  3509.         {
  3510.             amount = 0;
  3511.             curwin->w_cursor = cur_curpos;
  3512.  
  3513.             /* search backwards until we find something we recognize */
  3514.  
  3515.             while (curwin->w_cursor.lnum > 1)
  3516.             {
  3517.                 curwin->w_cursor.lnum--;
  3518.                 curwin->w_cursor.col = 0;
  3519.  
  3520.                 l = ml_get_curline();
  3521.  
  3522.                 /*
  3523.                  * If we're in a comment now, skip to the start of the comment.
  3524.                  */                                                /* XXX */
  3525.                 if ((trypos = find_start_comment(ind_maxcomment)) != NULL)
  3526.                 {
  3527.                     curwin->w_cursor.lnum = trypos->lnum + 1;
  3528.                     continue;
  3529.                 }
  3530.  
  3531.                 /*
  3532.                  * If the line looks like a function declaration, and we're
  3533.                  * not in a comment, put it the left margin.
  3534.                  */
  3535.                 if (isfuncdecl(theline))
  3536.                     break;
  3537.  
  3538.                 /* 
  3539.                  * Skip preprocessor directives and blank lines.
  3540.                  */
  3541.                 if (ispreproc(l))
  3542.                     continue;
  3543.  
  3544.                 if (commentorempty(l))
  3545.                     continue;
  3546.  
  3547.                 /* 
  3548.                  * If the PREVIOUS line is a function declaration, the current
  3549.                  * line (and the ones that follow) needs to be indented as
  3550.                  * parameters.
  3551.                  */
  3552.                 if (isfuncdecl(l))
  3553.                 {
  3554.                     amount = ind_param;
  3555.                     break;
  3556.                 }
  3557.  
  3558.                 /* 
  3559.                  * Doesn't look like anything interesting -- so just
  3560.                  * use the indent of this line.
  3561.                  * 
  3562.                  * Position the cursor over the rightmost paren, so that
  3563.                  * matching it will take us back to the start of the line.
  3564.                  */
  3565.                 find_last_paren(l);
  3566.  
  3567.                 if ((trypos = find_match_paren(ind_maxparen,
  3568.                                                      ind_maxcomment)) != NULL)
  3569.                     curwin->w_cursor.lnum = trypos->lnum;
  3570.                 amount = get_indent();        /* XXX */
  3571.                 break;
  3572.             }
  3573.         }
  3574.     }
  3575.  
  3576. theend:
  3577.     /* put the cursor back where it belongs */
  3578.     curwin->w_cursor = cur_curpos;
  3579.  
  3580.     vim_free(linecopy);
  3581.  
  3582.     if (amount < 0)
  3583.         return 0;
  3584.     return amount;
  3585. }
  3586.  
  3587.     static int
  3588. find_match(lookfor, ourscope, ind_maxparen, ind_maxcomment)
  3589.     int            lookfor;
  3590.     linenr_t    ourscope;
  3591.     int            ind_maxparen;
  3592.     int            ind_maxcomment;
  3593. {
  3594.     char_u        *look;
  3595.     FPOS        *theirscope;
  3596.     char_u        *mightbeif;
  3597.     int            elselevel;
  3598.     int            whilelevel;
  3599.  
  3600.     if (lookfor == LOOKFOR_IF)
  3601.     {
  3602.         elselevel = 1;
  3603.         whilelevel = 0;
  3604.     }
  3605.     else
  3606.     {
  3607.         elselevel = 0;
  3608.         whilelevel = 1;
  3609.     }
  3610.  
  3611.     curwin->w_cursor.col = 0;
  3612.  
  3613.     while (curwin->w_cursor.lnum > ourscope + 1)
  3614.     {
  3615.         curwin->w_cursor.lnum--;
  3616.         curwin->w_cursor.col = 0;
  3617.  
  3618.         look = skipwhite(ml_get_curline());
  3619.         if (iselse(look) || isif(look) || isdo(look) ||
  3620.              iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))  /* XXX */
  3621.         {
  3622.             /* 
  3623.              * if we've gone outside the braces entirely,
  3624.              * we must be out of scope...
  3625.              */
  3626.             theirscope = find_start_brace(ind_maxcomment);    /* XXX */
  3627.             if (theirscope == NULL)
  3628.                 break;
  3629.  
  3630.             /* 
  3631.              * and if the brace enclosing this is further
  3632.              * back than the one enclosing the else, we're
  3633.              * out of luck too.
  3634.              */
  3635.             if (theirscope->lnum < ourscope)
  3636.                 break;
  3637.  
  3638.             /* 
  3639.              * and if they're enclosed in a *deeper* brace,
  3640.              * then we can ignore it because it's in a
  3641.              * different scope...
  3642.              */
  3643.             if (theirscope->lnum > ourscope)
  3644.                 continue;
  3645.  
  3646.             /* 
  3647.              * if it was an "else" (that's not an "else if")
  3648.              * then we need to go back to another if, so 
  3649.              * increment elselevel
  3650.              */
  3651.             look = skipwhite(ml_get_curline());
  3652.             if (iselse(look))
  3653.             {
  3654.                 mightbeif = skipwhite(look + 4);
  3655.                 if (!isif(mightbeif))
  3656.                     ++elselevel;
  3657.                 continue;
  3658.             }
  3659.  
  3660.             /* 
  3661.              * if it was a "while" then we need to go back to
  3662.              * another "do", so increment whilelevel.
  3663.              */
  3664.             if (iswhileofdo(look, curwin->w_cursor.lnum, ind_maxparen))/* XXX */
  3665.             {
  3666.                 ++whilelevel;
  3667.                 continue;
  3668.             }
  3669.  
  3670.             /* If it's an "if" decrement elselevel */
  3671.             look = skipwhite(ml_get_curline());
  3672.             if (isif(look))
  3673.             {
  3674.                 elselevel--;
  3675.                 /*
  3676.                  * When looking for an "if" ignore "while"s that
  3677.                  * get in the way.
  3678.                  */
  3679.                 if (elselevel == 0 && lookfor == LOOKFOR_IF)
  3680.                     whilelevel = 0;
  3681.             }
  3682.  
  3683.             /* If it's a "do" decrement whilelevel */
  3684.             if (isdo(look))
  3685.                 whilelevel--;
  3686.  
  3687.             /* 
  3688.              * if we've used up all the elses, then
  3689.              * this must be the if that we want!
  3690.              * match the indent level of that if.
  3691.              */
  3692.             if (elselevel <= 0 && whilelevel <= 0)
  3693.             {
  3694.                 return OK;
  3695.             }
  3696.         }
  3697.     }
  3698.     return FAIL;
  3699. }
  3700.  
  3701. #endif /* CINDENT */
  3702.  
  3703. #ifdef LISPINDENT
  3704.     int
  3705. get_lisp_indent()
  3706. {
  3707.     FPOS        *pos, realpos;
  3708.     long        amount = 0;
  3709.     char_u        *that;
  3710.     colnr_t        col;
  3711.     colnr_t        maybe;
  3712.     colnr_t        firsttry;
  3713.  
  3714.  
  3715.     realpos = curwin->w_cursor;
  3716.     curwin->w_cursor.col = 0;
  3717.  
  3718.     if ((pos = findmatch('(')) != NULL)
  3719.     {
  3720.         curwin->w_cursor.lnum = pos->lnum;
  3721.         curwin->w_cursor.col = pos->col;
  3722.         col = pos->col;
  3723.  
  3724.         that = ml_get_curline();
  3725.         maybe = get_indent();        /* XXX */
  3726.  
  3727.         if (maybe == 0)
  3728.             amount = 2;
  3729.         else
  3730.         {
  3731.             while (*that && col)
  3732.             {
  3733.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3734.                 col--;
  3735.                 that++;
  3736.             }
  3737.  
  3738.              that++;
  3739.             amount++;
  3740.             firsttry = amount;
  3741.  
  3742.             /*
  3743.              * Go to the start of the second word.
  3744.              * If there is no second word, go back to firsttry.
  3745.              * Also stop at a '('.
  3746.              */
  3747.  
  3748.             while (vim_iswhite(*that))
  3749.             {
  3750.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3751.                 that++;
  3752.             }
  3753.             while (*that && !vim_iswhite(*that) && *that != '(')
  3754.             {
  3755.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3756.                 that++;
  3757.             }
  3758.             while (vim_iswhite(*that))
  3759.             {
  3760.                 amount += lbr_chartabsize(that, (colnr_t)amount);
  3761.                 that++;
  3762.             }
  3763.             if (! *that)
  3764.                 amount = firsttry;
  3765.         }
  3766.     }
  3767.     else    /* no matching '(' found, use indent of previous non-empty line */
  3768.     {
  3769.         while (curwin->w_cursor.lnum > 1)
  3770.         {
  3771.             --curwin->w_cursor.lnum;
  3772.             if (!linewhite(curwin->w_cursor.lnum))
  3773.                 break;
  3774.         }
  3775.         amount = get_indent();        /* XXX */
  3776.     }
  3777.  
  3778.     curwin->w_cursor = realpos;
  3779.  
  3780.     if (amount < 0)
  3781.         amount = 0;
  3782.     return (int)amount;
  3783. }
  3784. #endif /* LISPINDENT */
  3785.  
  3786. #if defined(UNIX) || defined(WIN32) || defined(__EMX__)
  3787. /*
  3788.  * Preserve files and exit.
  3789.  * When called IObuff must contain a message.
  3790.  */
  3791.     void
  3792. preserve_exit()
  3793. {
  3794.     BUF        *buf;
  3795.  
  3796. #ifdef USE_GUI
  3797.     if (gui.in_use)
  3798.     {
  3799.         gui.dying = TRUE;
  3800.         trash_output_buf();        /* trash any pending output */
  3801.     }
  3802.     else
  3803. #endif
  3804.     {
  3805.         windgoto((int)Rows - 1, 0);
  3806.  
  3807.         /*
  3808.          * Switch terminal mode back now, so these messages end up on the
  3809.          * "normal" screen (if there are two screens).
  3810.          */
  3811.         settmode(0);
  3812. #ifdef WIN32
  3813.         if (can_end_termcap_mode(FALSE) == TRUE)
  3814. #endif
  3815.             stoptermcap();
  3816.         flushbuf();
  3817.     }
  3818.  
  3819.     outstr(IObuff);
  3820.     screen_start();                    /* don't know where cursor is now */
  3821.     flushbuf();
  3822.  
  3823.     ml_close_notmod();                /* close all not-modified buffers */
  3824.  
  3825.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  3826.     {
  3827.         if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
  3828.         {
  3829.             OUTSTR("Vim: preserving files...\n");
  3830.             screen_start();            /* don't know where cursor is now */
  3831.             flushbuf();
  3832.             ml_sync_all(FALSE, FALSE);    /* preserve all swap files */
  3833.             break;
  3834.         }
  3835.     }
  3836.  
  3837.     ml_close_all(FALSE);            /* close all memfiles, without deleting */
  3838.  
  3839.     OUTSTR("Vim: Finished.\n");
  3840.  
  3841.     getout(1);
  3842. }
  3843. #endif /* defined(UNIX) || defined(WIN32) || defined(__EMX__) */
  3844.  
  3845. /*
  3846.  * return TRUE if "fname" exists.
  3847.  */
  3848.     int
  3849. vim_fexists(fname)
  3850.     char_u    *fname;
  3851. {
  3852.     struct stat st;
  3853.  
  3854.     if (stat((char *)fname, &st))
  3855.         return FALSE;
  3856.     return TRUE;
  3857. }
  3858.  
  3859. /*
  3860.  * Check for CTRL-C pressed, but only once in a while.
  3861.  * Should be used instead of mch_breakcheck() for functions that check for
  3862.  * each line in the file.  Calling mch_breakcheck() each time takes too much
  3863.  * time, because it can be a system call.
  3864.  */
  3865.  
  3866. #ifndef BREAKCHECK_SKIP
  3867. # define BREAKCHECK_SKIP 32
  3868. #endif
  3869.  
  3870.     void
  3871. line_breakcheck()
  3872. {
  3873.     static int    count = 0;
  3874.  
  3875.     if (++count == BREAKCHECK_SKIP)
  3876.     {
  3877.         count = 0;
  3878.         mch_breakcheck();
  3879.     }
  3880. }
  3881.  
  3882. /*
  3883.  * Free the list of files returned by ExpandWildCards() or other expansion
  3884.  * functions.
  3885.  */
  3886.     void
  3887. FreeWild(num, file)
  3888.     int        num;
  3889.     char_u    **file;
  3890. {
  3891.     if (file == NULL || num == 0)
  3892.         return;
  3893. #if defined(__EMX__) && defined(__ALWAYS_HAS_TRAILING_NULL_POINTER) /* XXX */
  3894.     /*
  3895.      * Is this still OK for when other functions thatn ExpandWildCards() have
  3896.      * been used???
  3897.      */
  3898.     _fnexplodefree((char **)file);
  3899. #else
  3900.     while (num--)
  3901.         vim_free(file[num]);
  3902.     vim_free(file);
  3903. #endif
  3904. }
  3905.  
  3906.